182 prev next chunks index CyanogenMod/android_packages_apps_Trebuchet_be217bf044892d49e427f000606308860a755585_src/com/android/launcher3/LauncherModel.java {strict: [[bs]], subset: [[bs]]}
line based (standard git) jfstmerge spork
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetProviderInfo;                                                          
  21 import android.content.BroadcastReceiver;                                                                
  22 import android.content.ComponentName;                                                                    
  23 import android.content.ContentProviderOperation;                                                         
  24 import android.content.ContentResolver;                                                                  
  25 import android.content.ContentValues;                                                                    
  26 import android.content.Context;                                                                          
  27 import android.content.Intent;                                                                           
  28 import android.content.Intent.ShortcutIconResource;                                                      
  29 import android.content.IntentFilter;                                                                     
  30 import android.content.pm.PackageManager;                                                                
  31 import android.content.pm.ProviderInfo;                                                                  
  32 import android.content.pm.ResolveInfo;                                                                   
  33 import android.database.Cursor;                                                                          
  34 import android.graphics.Bitmap;                                                                          
  35 import android.net.Uri;                                                                                  
  36 import android.os.Build;                                                                                 
  37 import android.os.Environment;                                                                           
  38 import android.os.Handler;                                                                               
  39 import android.os.HandlerThread;                                                                         
  40 import android.os.Looper;                                                                                
  41 import android.os.Parcelable;                                                                            
  42 import android.os.Process;                                                                               
  43 import android.os.SystemClock;                                                                           
  44 import android.os.TransactionTooLargeException;                                                          
  45 import android.provider.BaseColumns;                                                                     
  46 import android.text.TextUtils;                                                                           
  47 import android.util.Log;                                                                                 
  48 import android.util.LongSparseArray;                                                                     
  49 import android.util.Pair;                                                                                
  50                                                                                                          
  51 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  52 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  53 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  54 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  55 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  56 import com.android.launcher3.compat.UserHandleCompat;                                                    
  57 import com.android.launcher3.compat.UserManagerCompat;                                                   
  58 import com.android.launcher3.model.WidgetsModel;                                                         
  59 import com.android.launcher3.util.ComponentKey;                                                          
  60 import com.android.launcher3.util.CursorIconInfo;                                                        
  61 import com.android.launcher3.util.LongArrayMap;                                                          
  62 import com.android.launcher3.util.ManagedProfileHeuristic;                                               
  63 import com.android.launcher3.util.Thunk;                                                                 
  64                                                                                                          
  65 import java.lang.ref.WeakReference;                                                                      
  66 import java.net.URISyntaxException;                                                                      
  67 import java.security.InvalidParameterException;                                                          
  68 import java.util.ArrayList;                                                                              
  69 import java.util.Arrays;                                                                                 
  70 import java.util.Collection;                                                                             
  71 import java.util.Collections;                                                                            
  72 import java.util.Comparator;                                                                             
  73 import java.util.HashMap;                                                                                
  74 import java.util.HashSet;                                                                                
  75 import java.util.Iterator;                                                                               
  76 import java.util.List;                                                                                   
  77 import java.util.Map.Entry;                                                                              
  78 import java.util.Set;                                                                                    
  79                                                                                                          
  80 /**                                                                                                      
  81  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  82  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  83  * for the Launcher.                                                                                     
  84  */                                                                                                      
  85 public class LauncherModel extends BroadcastReceiver                                                     
  86         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                      
  87     static final boolean DEBUG_LOADERS = false;                                                          
  88     private static final boolean DEBUG_RECEIVER = false;                                                 
  89     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  90                                                                                                          
  91     static final String TAG = "Launcher.Model";                                                          
  92                                                                                                          
  93     public static final int LOADER_FLAG_NONE = 0;                                                        
  94     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  95     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  96                                                                                                          
  97     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  98     private static final long INVALID_SCREEN_ID = -1L;                                                   
  99                                                                                                          
 100     @Thunk final boolean mAppsCanBeOnRemoveableStorage;                                                  
 101     private final boolean mOldContentProviderExists;                                                     
 102                                                                                                          
 103     @Thunk final LauncherAppState mApp;                                                                  
 104     @Thunk final Object mLock = new Object();                                                            
 105     @Thunk DeferredHandler mHandler = new DeferredHandler();                                             
 106     @Thunk LoaderTask mLoaderTask;                                                                       
 107     @Thunk boolean mIsLoaderTaskRunning;                                                                 
 108     @Thunk boolean mHasLoaderCompletedOnce;                                                              
 109                                                                                                          
 110     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 111                                                                                                          
 112     @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");              
 113     static {                                                                                             
 114         sWorkerThread.start();                                                                           
 115     }                                                                                                    
 116     @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());                        
 117                                                                                                          
 118     // We start off with everything not loaded.  After that, we assume that                              
 119     // our monitoring of the package manager provides all updates and we never                           
 120     // need to do a requery.  These are only ever touched from the loader thread.                        
 121     @Thunk boolean mWorkspaceLoaded;                                                                     
 122     @Thunk boolean mAllAppsLoaded;                                                                       
 123                                                                                                          
 124     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 125     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 126     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 127     // a normal load, we also clear this set of Runnables.                                               
 128     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 129                                                                                                          
 130     /**                                                                                                  
 131      * Set of runnables to be called on the background thread after the workspace binding                
 132      * is complete.                                                                                      
 133      */                                                                                                  
 134     static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();                 
 135                                                                                                          
 136     @Thunk WeakReference<Callbacks> mCallbacks;                                                          
 137                                                                                                          
 138     // < only access in worker thread >                                                                  
 139     AllAppsList mBgAllAppsList;                                                                          
 140     // Entire list of widgets.                                                                           
 141     WidgetsModel mBgWidgetsModel;                                                                        
 142                                                                                                          
 143     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 144     // other locks, this one can generally be held long-term because we never expect any of these        
 145     // static data structures to be referenced outside of the worker thread except on the first          
 146     // load after configuration change.                                                                  
 147     static final Object sBgLock = new Object();                                                          
 148                                                                                                          
 149     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 150     // LauncherModel to their ids                                                                        
 151     static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();                            
 152                                                                                                          
 153     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 154     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 155     //       shortcuts within folders).                                                                  
 156     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 157                                                                                                          
 158     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 159     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 160         new ArrayList<LauncherAppWidgetInfo>();                                                          
 161                                                                                                          
 162     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 163     static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();                             
 164                                                                                                          
 165     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 166     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 167                                                                                                          
 168     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 169     public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;               
 170                                                                                                          
 171     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 172     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                           
 173             new HashMap<UserHandleCompat, HashSet<String>>();                                            
 174                                                                                                          
 175     // </ only access in worker thread >                                                                 
 176                                                                                                          
 177     @Thunk IconCache mIconCache;                                                                         
 178                                                                                                          
 179     @Thunk final LauncherAppsCompat mLauncherApps;                                                       
 180     @Thunk final UserManagerCompat mUserManager;                                                         
 181                                                                                                          
 182     public interface Callbacks {                                                                         
 183         public boolean setLoadOnResume();                                                                
 184         public int getCurrentWorkspaceScreen();                                                          
 185         public void startBinding();                                                                      
 186         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 187                               boolean forceAnimateIcons);                                                
 188         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 189         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 190         public void bindFolders(LongArrayMap<FolderInfo> folders);                                       
 191         public void finishBindingItems();                                                                
 192         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 193         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 194         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 195                                   ArrayList<ItemInfo> addNotAnimated,                                    
 196                                   ArrayList<ItemInfo> addAnimated,                                       
 197                                   ArrayList<AppInfo> addedApps);                                         
 198         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 199         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                
 200                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                 
 201         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                       
 202         public void bindRestoreItemsChange(HashSet<ItemInfo> updates);                                   
 203         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 204                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                 
 205         public void bindAllPackages(WidgetsModel model);                                                 
 206         public void bindSearchablesChanged();                                                            
 207         public boolean isAllAppsButtonRank(int rank);                                                    
 208         public void onPageBoundSynchronously(int page);                                                  
 209         public void dumpLogsToLocalData();                                                               
 210     }                                                                                                    
 211                                                                                                          
 212     public interface ItemInfoFilter {                                                                    
 213         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 214     }                                                                                                    
 215                                                                                                          
 216     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 217         Context context = app.getContext();                                                              
 218                                                                                                          
 219         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 220         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 221         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 222         // resource string.                                                                              
 223         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 224         ProviderInfo providerInfo =                                                                      
 225                 context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                
 226         ProviderInfo redirectProvider =                                                                  
 227                 context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                
 228                                                                                                          
 229         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 230         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 231                                                                                                          
 232         if (mOldContentProviderExists) {                                                                 
 233             Log.d(TAG, "Old launcher provider exists.");                                                 
 234         } else {                                                                                         
 235             Log.d(TAG, "Old launcher provider does not exist.");                                         
 236         }                                                                                                
 237                                                                                                          
 238         mApp = app;                                                                                      
 239         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 240         mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);                               
 241         mIconCache = iconCache;                                                                          
 242                                                                                                          
 243         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 244         mUserManager = UserManagerCompat.getInstance(context);                                           
 245     }                                                                                                    
 246                                                                                                          
 247     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 248      * posted on the main thread handler. */                                                             
 249     @Thunk void runOnMainThread(Runnable r) {                                                            
 250         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 251             // If we are on the worker thread, post onto the main handler                                
 252             mHandler.post(r);                                                                            
 253         } else {                                                                                         
 254             r.run();                                                                                     
 255         }                                                                                                
 256     }                                                                                                    
 257                                                                                                          
 258     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 259      * posted on the worker thread handler. */                                                           
 260     private static void runOnWorkerThread(Runnable r) {                                                  
 261         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 262             r.run();                                                                                     
 263         } else {                                                                                         
 264             // If we are not on the worker thread, then post to the worker handler                       
 265             sWorker.post(r);                                                                             
 266         }                                                                                                
 267     }                                                                                                    
 268                                                                                                          
 269     /**                                                                                                  
 270      * Runs the specified runnable after the loader is complete                                          
 271      */                                                                                                  
 272     @Thunk void runAfterBindCompletes(Runnable r) {                                                      
 273         if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) {                                          
 274             synchronized (mBindCompleteRunnables) {                                                      
 275                 mBindCompleteRunnables.add(r);                                                           
 276             }                                                                                            
 277         } else {                                                                                         
 278             runOnWorkerThread(r);                                                                        
 279         }                                                                                                
 280     }                                                                                                    
 281                                                                                                          
 282     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 283         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 284     }                                                                                                    
 285                                                                                                          
 286     public void setPackageState(final PackageInstallInfo installInfo) {                                  
 287         Runnable updateRunnable = new Runnable() {                                                       
 288                                                                                                          
 289             @Override                                                                                    
 290             public void run() {                                                                          
 291                 synchronized (sBgLock) {                                                                 
 292                     final HashSet<ItemInfo> updates = new HashSet<>();                                   
 293                                                                                                          
 294                     if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                  
 295                         // Ignore install success events as they are handled by Package add events.      
 296                         return;                                                                          
 297                     }                                                                                    
 298                                                                                                          
 299                     for (ItemInfo info : sBgItemsIdMap) {                                                
 300                         if (info instanceof ShortcutInfo) {                                              
 301                             ShortcutInfo si = (ShortcutInfo) info;                                       
 302                             ComponentName cn = si.getTargetComponent();                                  
 303                             if (si.isPromise() && (cn != null)                                           
 304                                     && installInfo.packageName.equals(cn.getPackageName())) {            
 305                                 si.setInstallProgress(installInfo.progress);                             
 306                                                                                                          
 307                                 if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {         
 308                                     // Mark this info as broken.                                         
 309                                     si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;              
 310                                 }                                                                        
 311                                 updates.add(si);                                                         
 312                             }                                                                            
 313                         }                                                                                
 314                     }                                                                                    
 315                                                                                                          
 316                     for (LauncherAppWidgetInfo widget : sBgAppWidgets) {                                 
 317                         if (widget.providerName.getPackageName().equals(installInfo.packageName)) {      
 318                             widget.installProgress = installInfo.progress;                               
 319                             updates.add(widget);                                                         
 320                         }                                                                                
 321                     }                                                                                    
 322                                                                                                          
 323                     if (!updates.isEmpty()) {                                                            
 324                         // Push changes to the callback.                                                 
 325                         Runnable r = new Runnable() {                                                    
 326                             public void run() {                                                          
 327                                 Callbacks callbacks = getCallback();                                     
 328                                 if (callbacks != null) {                                                 
 329                                     callbacks.bindRestoreItemsChange(updates);                           
 330                                 }                                                                        
 331                             }                                                                            
 332                         };                                                                               
 333                         mHandler.post(r);                                                                
 334                     }                                                                                    
 335                 }                                                                                        
 336             }                                                                                            
 337         };                                                                                               
 338         runOnWorkerThread(updateRunnable);                                                               
 339     }                                                                                                    
 340                                                                                                          
 341     /**                                                                                                  
 342      * Updates the icons and label of all pending icons for the provided package name.                   
 343      */                                                                                                  
 344     public void updateSessionDisplayInfo(final String packageName) {                                     
 345         Runnable updateRunnable = new Runnable() {                                                       
 346                                                                                                          
 347             @Override                                                                                    
 348             public void run() {                                                                          
 349                 synchronized (sBgLock) {                                                                 
 350                     final ArrayList<ShortcutInfo> updates = new ArrayList<>();                           
 351                     final UserHandleCompat user = UserHandleCompat.myUserHandle();                       
 352                                                                                                          
 353                     for (ItemInfo info : sBgItemsIdMap) {                                                
 354                         if (info instanceof ShortcutInfo) {                                              
 355                             ShortcutInfo si = (ShortcutInfo) info;                                       
 356                             ComponentName cn = si.getTargetComponent();                                  
 357                             if (si.isPromise() && (cn != null)                                           
 358                                     && packageName.equals(cn.getPackageName())) {                        
 359                                 if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {               
 360                                     // For auto install apps update the icon as well as label.           
 361                                     mIconCache.getTitleAndIcon(si,                                       
 362                                             si.promisedIntent, user,                                     
 363                                             si.shouldUseLowResIcon());                                   
 364                                 } else {                                                                 
 365                                     // Only update the icon for restored apps.                           
 366                                     si.updateIcon(mIconCache);                                           
 367                                 }                                                                        
 368                                 updates.add(si);                                                         
 369                             }                                                                            
 370                         }                                                                                
 371                     }                                                                                    
 372                                                                                                          
 373                     if (!updates.isEmpty()) {                                                            
 374                         // Push changes to the callback.                                                 
 375                         Runnable r = new Runnable() {                                                    
 376                             public void run() {                                                          
 377                                 Callbacks callbacks = getCallback();                                     
 378                                 if (callbacks != null) {                                                 
 379                                     callbacks.bindShortcutsChanged(updates,                              
 380                                             new ArrayList<ShortcutInfo>(), user);                        
 381                                 }                                                                        
 382                             }                                                                            
 383                         };                                                                               
 384                         mHandler.post(r);                                                                
 385                     }                                                                                    
 386                 }                                                                                        
 387             }                                                                                            
 388         };                                                                                               
 389         runOnWorkerThread(updateRunnable);                                                               
 390     }                                                                                                    
 391                                                                                                          
 392     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 393         final Callbacks callbacks = getCallback();                                                       
 394                                                                                                          
 395         if (allAppsApps == null) {                                                                       
 396             throw new RuntimeException("allAppsApps must not be null");                                  
 397         }                                                                                                
 398         if (allAppsApps.isEmpty()) {                                                                     
 399             return;                                                                                      
 400         }                                                                                                
 401                                                                                                          
 402         // Process the newly added applications and add them to the database first                       
 403         Runnable r = new Runnable() {                                                                    
 404             public void run() {                                                                          
 405                 runOnMainThread(new Runnable() {                                                         
 406                     public void run() {                                                                  
 407                         Callbacks cb = getCallback();                                                    
 408                         if (callbacks == cb && cb != null) {                                             
 409                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 410                         }                                                                                
 411                     }                                                                                    
 412                 });                                                                                      
 413             }                                                                                            
 414         };                                                                                               
 415         runOnWorkerThread(r);                                                                            
 416     }                                                                                                    
 417                                                                                                          
 418     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,           
 419             int[] xy, int spanX, int spanY) {                                                            
 420         LauncherAppState app = LauncherAppState.getInstance();                                           
 421         InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                
 422         final int xCount = (int) profile.numColumns;                                                     
 423         final int yCount = (int) profile.numRows;                                                        
 424         boolean[][] occupied = new boolean[xCount][yCount];                                              
 425         if (occupiedPos != null) {                                                                       
 426             for (ItemInfo r : occupiedPos) {                                                             
 427                 int right = r.cellX + r.spanX;                                                           
 428                 int bottom = r.cellY + r.spanY;                                                          
 429                 for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {                          
 430                     for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {                     
 431                         occupied[x][y] = true;                                                           
 432                     }                                                                                    
 433                 }                                                                                        
 434             }                                                                                            
 435         }                                                                                                
 436         return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                     
 437     }                                                                                                    
 438                                                                                                          
 439     /**                                                                                                  
 440      * Find a position on the screen for the given size or adds a new screen.                            
 441      * @return screenId and the coordinates for the item.                                                
 442      */                                                                                                  
 443     @Thunk Pair<Long, int[]> findSpaceForItem(                                                           
 444             Context context,                                                                             
 445             ArrayList<Long> workspaceScreens,                                                            
 446             ArrayList<Long> addedWorkspaceScreensFinal,                                                  
 447             int spanX, int spanY) {                                                                      
 448         LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();                      
 449                                                                                                          
 450         // Use sBgItemsIdMap as all the items are already loaded.                                        
 451         assertWorkspaceLoaded();                                                                         
 452         synchronized (sBgLock) {                                                                         
 453             for (ItemInfo info : sBgItemsIdMap) {                                                        
 454                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
 455                     ArrayList<ItemInfo> items = screenItems.get(info.screenId);                          
 456                     if (items == null) {                                                                 
 457                         items = new ArrayList<>();                                                       
 458                         screenItems.put(info.screenId, items);                                           
 459                     }                                                                                    
 460                     items.add(info);                                                                     
 461                 }                                                                                        
 462             }                                                                                            
 463         }                                                                                                
 464                                                                                                          
 465         // Find appropriate space for the item.                                                          
 466         long screenId = 0;                                                                               
 467         int[] cordinates = new int[2];                                                                   
 468         boolean found = false;                                                                           
 469                                                                                                          
 470         int screenCount = workspaceScreens.size();                                                       
 471         // First check the preferred screen.                                                             
 472         int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;                                   
 473         if (preferredScreenIndex < screenCount) {                                                        
 474             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 475             found = findNextAvailableIconSpaceInScreen(                                                  
 476                     screenItems.get(screenId), cordinates, spanX, spanY);                                
 477         }                                                                                                
 478                                                                                                          
 479         if (!found) {                                                                                    
 480             // Search on any of the screens starting from the first screen.                              
 481             for (int screen = 1; screen < screenCount; screen++) {                                       
 482                 screenId = workspaceScreens.get(screen);                                                 
 483                 if (findNextAvailableIconSpaceInScreen(                                                  
 484                         screenItems.get(screenId), cordinates, spanX, spanY)) {                          
 485                     // We found a space for it                                                           
 486                     found = true;                                                                        
 487                     break;                                                                               
 488                 }                                                                                        
 489             }                                                                                            
 490         }                                                                                                
 491                                                                                                          
 492         if (!found) {                                                                                    
 493             // Still no position found. Add a new screen to the end.                                     
 494             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 495                                                                                                          
 496             // Save the screen id for binding in the workspace                                           
 497             workspaceScreens.add(screenId);                                                              
 498             addedWorkspaceScreensFinal.add(screenId);                                                    
 499                                                                                                          
 500             // If we still can't find an empty space, then God help us all!!!                            
 501             if (!findNextAvailableIconSpaceInScreen(                                                     
 502                     screenItems.get(screenId), cordinates, spanX, spanY)) {                              
 503                 throw new RuntimeException("Can't find space to add the item");                          
 504             }                                                                                            
 505         }                                                                                                
 506         return Pair.create(screenId, cordinates);                                                        
 507     }                                                                                                    
 508                                                                                                          
 509     /**                                                                                                  
 510      * Adds the provided items to the workspace.                                                         
 511      */                                                                                                  
 512     public void addAndBindAddedWorkspaceItems(final Context context,                                     
 513             final ArrayList<? extends ItemInfo> workspaceApps) {                                         
 514         final Callbacks callbacks = getCallback();                                                       
 515         if (workspaceApps.isEmpty()) {                                                                   
 516             return;                                                                                      
 517         }                                                                                                
 518         // Process the newly added applications and add them to the database first                       
 519         Runnable r = new Runnable() {                                                                    
 520             public void run() {                                                                          
 521                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 522                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 523                                                                                                          
 524                 // Get the list of workspace screens.  We need to append to this list and                
 525                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 526                 // called.                                                                               
 527                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 528                 synchronized(sBgLock) {                                                                  
 529                     for (ItemInfo item : workspaceApps) {                                                
 530                         if (item instanceof ShortcutInfo) {                                              
 531                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 532                             if (shortcutExists(context, item.getIntent(), item.user)) {                  
 533                                 continue;                                                                
 534                             }                                                                            
 535                         }                                                                                
 536                                                                                                          
 537                         // Find appropriate space for the item.                                          
 538                         Pair<Long, int[]> coords = findSpaceForItem(context,                             
 539                                 workspaceScreens, addedWorkspaceScreensFinal,                            
 540                                 1, 1);                                                                   
 541                         long screenId = coords.first;                                                    
 542                         int[] cordinates = coords.second;                                                
 543                                                                                                          
 544                         ItemInfo itemInfo;                                                               
 545                         if (item instanceof ShortcutInfo || item instanceof FolderInfo) {                
 546                             itemInfo = item;                                                             
 547                         } else if (item instanceof AppInfo) {                                            
 548                             itemInfo = ((AppInfo) item).makeShortcut();                                  
 549                         } else {                                                                         
 550                             throw new RuntimeException("Unexpected info type");                          
 551                         }                                                                                
 552                                                                                                          
 553                         // Add the shortcut to the db                                                    
 554                         addItemToDatabase(context, itemInfo,                                             
 555                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 556                                 screenId, cordinates[0], cordinates[1]);                                 
 557                         // Save the ShortcutInfo for binding in the workspace                            
 558                         addedShortcutsFinal.add(itemInfo);                                               
 559                     }                                                                                    
 560                 }                                                                                        
 561                                                                                                          
 562                 // Update the workspace screens                                                          
 563                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 564                                                                                                          
 565                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 566                     runOnMainThread(new Runnable() {                                                     
 567                         public void run() {                                                              
 568                             Callbacks cb = getCallback();                                                
 569                             if (callbacks == cb && cb != null) {                                         
 570                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 571                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 572                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 573                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 574                                     long lastScreenId = info.screenId;                                   
 575                                     for (ItemInfo i : addedShortcutsFinal) {                             
 576                                         if (i.screenId == lastScreenId) {                                
 577                                             addAnimated.add(i);                                          
 578                                         } else {                                                         
 579                                             addNotAnimated.add(i);                                       
 580                                         }                                                                
 581                                     }                                                                    
 582                                 }                                                                        
 583                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 584                                         addNotAnimated, addAnimated, null);                              
 585                             }                                                                            
 586                         }                                                                                
 587                     });                                                                                  
 588                 }                                                                                        
 589             }                                                                                            
 590         };                                                                                               
 591         runOnWorkerThread(r);                                                                            
 592     }                                                                                                    
 593                                                                                                          
 594     private void unbindItemInfosAndClearQueuedBindRunnables() {                                          
 595         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 596             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 597                     "main thread");                                                                      
 598         }                                                                                                
 599                                                                                                          
 600         // Clear any deferred bind runnables                                                             
 601         synchronized (mDeferredBindRunnables) {                                                          
 602             mDeferredBindRunnables.clear();                                                              
 603         }                                                                                                
 604                                                                                                          
 605         // Remove any queued UI runnables                                                                
 606         mHandler.cancelAll();                                                                            
 607         // Unbind all the workspace items                                                                
 608         unbindWorkspaceItemsOnMainThread();                                                              
 609     }                                                                                                    
 610                                                                                                          
 611     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 612     void unbindWorkspaceItemsOnMainThread() {                                                            
 613         // Ensure that we don't use the same workspace items data structure on the main thread           
 614         // by making a copy of workspace items first.                                                    
 615         final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();                                  
 616         synchronized (sBgLock) {                                                                         
 617             tmpItems.addAll(sBgWorkspaceItems);                                                          
 618             tmpItems.addAll(sBgAppWidgets);                                                              
 619         }                                                                                                
 620         Runnable r = new Runnable() {                                                                    
 621                 @Override                                                                                
 622                 public void run() {                                                                      
 623                    for (ItemInfo item : tmpItems) {                                                      
 624                        item.unbind();                                                                    
 625                    }                                                                                     
 626                 }                                                                                        
 627             };                                                                                           
 628         runOnMainThread(r);                                                                              
 629     }                                                                                                    
 630                                                                                                          
 631     /**                                                                                                  
 632      * Adds an item to the DB if it was not created previously, or move it to a new                      
 633      * <container, screen, cellX, cellY>                                                                 
 634      */                                                                                                  
 635     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 636             long screenId, int cellX, int cellY) {                                                       
 637         if (item.container == ItemInfo.NO_ID) {                                                          
 638             // From all apps                                                                             
 639             addItemToDatabase(context, item, container, screenId, cellX, cellY);                         
 640         } else {                                                                                         
 641             // From somewhere else                                                                       
 642             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 643         }                                                                                                
 644     }                                                                                                    
 645                                                                                                          
 646     static void checkItemInfoLocked(                                                                     
 647             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 648         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 649         if (modelItem != null && item != modelItem) {                                                    
 650             // check all the data is consistent                                                          
 651             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 652                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 653                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 654                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 655                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 656                         modelShortcut.id == shortcut.id &&                                               
 657                         modelShortcut.itemType == shortcut.itemType &&                                   
 658                         modelShortcut.container == shortcut.container &&                                 
 659                         modelShortcut.screenId == shortcut.screenId &&                                   
 660                         modelShortcut.cellX == shortcut.cellX &&                                         
 661                         modelShortcut.cellY == shortcut.cellY &&                                         
 662                         modelShortcut.spanX == shortcut.spanX &&                                         
 663                         modelShortcut.spanY == shortcut.spanY &&                                         
 664                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 665                         (modelShortcut.dropPos != null &&                                                
 666                                 shortcut.dropPos != null &&                                              
 667                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 668                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 669                     // For all intents and purposes, this is the same object                             
 670                     return;                                                                              
 671                 }                                                                                        
 672             }                                                                                            
 673                                                                                                          
 674             // the modelItem needs to match up perfectly with item if our model is                       
 675             // to be consistent with the database-- for now, just require                                
 676             // modelItem == item or the equality check above                                             
 677             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 678                     "modelItem: " +                                                                      
 679                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 680                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 681             RuntimeException e = new RuntimeException(msg);                                              
 682             if (stackTrace != null) {                                                                    
 683                 e.setStackTrace(stackTrace);                                                             
 684             }                                                                                            
 685             throw e;                                                                                     
 686         }                                                                                                
 687     }                                                                                                    
 688                                                                                                          
 689     static void checkItemInfo(final ItemInfo item) {                                                     
 690         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 691         final long itemId = item.id;                                                                     
 692         Runnable r = new Runnable() {                                                                    
 693             public void run() {                                                                          
 694                 synchronized (sBgLock) {                                                                 
 695                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 696                 }                                                                                        
 697             }                                                                                            
 698         };                                                                                               
 699         runOnWorkerThread(r);                                                                            
 700     }                                                                                                    
 701                                                                                                          
 702     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 703             final ItemInfo item, final String callingFunction) {                                         
 704         final long itemId = item.id;                                                                     
 705         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                                
 706         final ContentResolver cr = context.getContentResolver();                                         
 707                                                                                                          
 708         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 709         Runnable r = new Runnable() {                                                                    
 710             public void run() {                                                                          
 711                 cr.update(uri, values, null, null);                                                      
 712                 updateItemArrays(item, itemId, stackTrace);                                              
 713             }                                                                                            
 714         };                                                                                               
 715         runOnWorkerThread(r);                                                                            
 716     }                                                                                                    
 717                                                                                                          
 718     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 719             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 720         final ContentResolver cr = context.getContentResolver();                                         
 721                                                                                                          
 722         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 723         Runnable r = new Runnable() {                                                                    
 724             public void run() {                                                                          
 725                 ArrayList<ContentProviderOperation> ops =                                                
 726                         new ArrayList<ContentProviderOperation>();                                       
 727                 int count = items.size();                                                                
 728                 for (int i = 0; i < count; i++) {                                                        
 729                     ItemInfo item = items.get(i);                                                        
 730                     final long itemId = item.id;                                                         
 731                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                    
 732                     ContentValues values = valuesList.get(i);                                            
 733                                                                                                          
 734                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 735                     updateItemArrays(item, itemId, stackTrace);                                          
 736                                                                                                          
 737                 }                                                                                        
 738                 try {                                                                                    
 739                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 740                 } catch (Exception e) {                                                                  
 741                     e.printStackTrace();                                                                 
 742                 }                                                                                        
 743             }                                                                                            
 744         };                                                                                               
 745         runOnWorkerThread(r);                                                                            
 746     }                                                                                                    
 747                                                                                                          
 748     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 749         // Lock on mBgLock *after* the db operation                                                      
 750         synchronized (sBgLock) {                                                                         
 751             checkItemInfoLocked(itemId, item, stackTrace);                                               
 752                                                                                                          
 753             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 754                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 755                 // Item is in a folder, make sure this folder exists                                     
 756                 if (!sBgFolders.containsKey(item.container)) {                                           
 757                     // An items container is being set to a that of an item which is not in              
 758                     // the list of Folders.                                                              
 759                     String msg = "item: " + item + " container being set to: " +                         
 760                             item.container + ", not in the list of folders";                             
 761                     Log.e(TAG, msg);                                                                     
 762                 }                                                                                        
 763             }                                                                                            
 764                                                                                                          
 765             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 766             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 767             // that are on the desktop, as appropriate                                                   
 768             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 769             if (modelItem != null &&                                                                     
 770                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 771                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 772                 switch (modelItem.itemType) {                                                            
 773                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 774                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 775                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 776                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 777                             sBgWorkspaceItems.add(modelItem);                                            
 778                         }                                                                                
 779                         break;                                                                           
 780                     default:                                                                             
 781                         break;                                                                           
 782                 }                                                                                        
 783             } else {                                                                                     
 784                 sBgWorkspaceItems.remove(modelItem);                                                     
 785             }                                                                                            
 786         }                                                                                                
 787     }                                                                                                    
 788                                                                                                          
 789     /**                                                                                                  
 790      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 791      */                                                                                                  
 792     public static void moveItemInDatabase(Context context, final ItemInfo item, final long container,    
 793             final long screenId, final int cellX, final int cellY) {                                     
 794         item.container = container;                                                                      
 795         item.cellX = cellX;                                                                              
 796         item.cellY = cellY;                                                                              
 797                                                                                                          
 798         // We store hotseat items in canonical form which is this orientation invariant position         
 799         // in the hotseat                                                                                
 800         if (context instanceof Launcher && screenId < 0 &&                                               
 801                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 802             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 803         } else {                                                                                         
 804             item.screenId = screenId;                                                                    
 805         }                                                                                                
 806                                                                                                          
 807         final ContentValues values = new ContentValues();                                                
 808         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 809         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 810         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 811         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 812         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 813                                                                                                          
 814         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 815     }                                                                                                    
 816                                                                                                          
 817     /**                                                                                                  
 818      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 819      * cellX, cellY have already been updated on the ItemInfos.                                          
 820      */                                                                                                  
 821     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 822             final long container, final int screen) {                                                    
 823                                                                                                          
 824         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 825         int count = items.size();                                                                        
 826                                                                                                          
 827         for (int i = 0; i < count; i++) {                                                                
 828             ItemInfo item = items.get(i);                                                                
 829             item.container = container;                                                                  
 830                                                                                                          
 831             // We store hotseat items in canonical form which is this orientation invariant position     
 832             // in the hotseat                                                                            
 833             if (context instanceof Launcher && screen < 0 &&                                             
 834                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 835                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 836                         item.cellY);                                                                     
 837             } else {                                                                                     
 838                 item.screenId = screen;                                                                  
 839             }                                                                                            
 840                                                                                                          
 841             final ContentValues values = new ContentValues();                                            
 842             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 843             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 844             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 845             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 846             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 847                                                                                                          
 848             contentValues.add(values);                                                                   
 849         }                                                                                                
 850         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 851     }                                                                                                    
 852                                                                                                          
 853     /**                                                                                                  
 854      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 855      */                                                                                                  
 856     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 857             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 858         item.container = container;                                                                      
 859         item.cellX = cellX;                                                                              
 860         item.cellY = cellY;                                                                              
 861         item.spanX = spanX;                                                                              
 862         item.spanY = spanY;                                                                              
 863                                                                                                          
 864         // We store hotseat items in canonical form which is this orientation invariant position         
 865         // in the hotseat                                                                                
 866         if (context instanceof Launcher && screenId < 0 &&                                               
 867                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 868             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 869         } else {                                                                                         
 870             item.screenId = screenId;                                                                    
 871         }                                                                                                
 872                                                                                                          
 873         final ContentValues values = new ContentValues();                                                
 874         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 875         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 876         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 877         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 878         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 879         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 880         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 881                                                                                                          
 882         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 883     }                                                                                                    
 884                                                                                                          
 885     /**                                                                                                  
 886      * Update an item to the database in a specified container.                                          
 887      */                                                                                                  
 888     public static void updateItemInDatabase(Context context, final ItemInfo item) {                      
 889         final ContentValues values = new ContentValues();                                                
 890         item.onAddToDatabase(context, values);                                                           
 891         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 892     }                                                                                                    
 893                                                                                                          
 894     private void assertWorkspaceLoaded() {                                                               
 895         if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) {   
 896             throw new RuntimeException("Trying to add shortcut while loader is running");                
 897         }                                                                                                
 898     }                                                                                                    
 899                                                                                                          
 900     /**                                                                                                  
 901      * Returns true if the shortcuts already exists on the workspace. This must be called after          
 902      * the workspace has been loaded. We identify a shortcut by its intent.                              
 903      */                                                                                                  
 904     @Thunk boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {               
 905         assertWorkspaceLoaded();                                                                         
 906         final String intentWithPkg, intentWithoutPkg;                                                    
 907         if (intent.getComponent() != null) {                                                             
 908             // If component is not null, an intent with null package will produce                        
 909             // the same result and should also be a match.                                               
 910             String packageName = intent.getComponent().getPackageName();                                 
 911             if (intent.getPackage() != null) {                                                           
 912                 intentWithPkg = intent.toUri(0);                                                         
 913                 intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);                         
 914             } else {                                                                                     
 915                 intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);                     
 916                 intentWithoutPkg = intent.toUri(0);                                                      
 917             }                                                                                            
 918         } else {                                                                                         
 919             intentWithPkg = intent.toUri(0);                                                             
 920             intentWithoutPkg = intent.toUri(0);                                                          
 921         }                                                                                                
 922                                                                                                          
 923         synchronized (sBgLock) {                                                                         
 924             for (ItemInfo item : sBgItemsIdMap) {                                                        
 925                 if (item instanceof ShortcutInfo) {                                                      
 926                     ShortcutInfo info = (ShortcutInfo) item;                                             
 927                     Intent targetIntent = info.promisedIntent == null                                    
 928                             ? info.intent : info.promisedIntent;                                         
 929                     if (targetIntent != null && info.user.equals(user)) {                                
 930                         String s = targetIntent.toUri(0);                                                
 931                         if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {                     
 932                             return true;                                                                 
 933                         }                                                                                
 934                     }                                                                                    
 935                 }                                                                                        
 936             }                                                                                            
 937         }                                                                                                
 938         return false;                                                                                    
 939     }                                                                                                    
 940                                                                                                          
 941     /**                                                                                                  
 942      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 943      */                                                                                                  
 944     FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {            
 945         final ContentResolver cr = context.getContentResolver();                                         
 946         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 947                 "_id=? and (itemType=? or itemType=?)",                                                  
 948                 new String[] { String.valueOf(id),                                                       
 949                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 950                                                                                                          
 951         try {                                                                                            
 952             if (c.moveToFirst()) {                                                                       
 953                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 954                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 955                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 956                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 957                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 958                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 959                 final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);    
 960                                                                                                          
 961                 FolderInfo folderInfo = null;                                                            
 962                 switch (c.getInt(itemTypeIndex)) {                                                       
 963                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 964                         folderInfo = findOrMakeFolder(folderList, id);                                   
 965                         break;                                                                           
 966                 }                                                                                        
 967                                                                                                          
 968                 // Do not trim the folder label, as is was set by the user.                              
 969                 folderInfo.title = c.getString(titleIndex);                                              
 970                 folderInfo.id = id;                                                                      
 971                 folderInfo.container = c.getInt(containerIndex);                                         
 972                 folderInfo.screenId = c.getInt(screenIndex);                                             
 973                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 974                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 975                 folderInfo.options = c.getInt(optionsIndex);                                             
 976                                                                                                          
 977                 return folderInfo;                                                                       
 978             }                                                                                            
 979         } finally {                                                                                      
 980             c.close();                                                                                   
 981         }                                                                                                
 982                                                                                                          
 983         return null;                                                                                     
 984     }                                                                                                    
 985                                                                                                          
 986     /**                                                                                                  
 987      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 988      * cellY fields of the item. Also assigns an ID to the item.                                         
 989      */                                                                                                  
 990     public static void addItemToDatabase(Context context, final ItemInfo item, final long container,     
 991             final long screenId, final int cellX, final int cellY) {                                     
 992         item.container = container;                                                                      
 993         item.cellX = cellX;                                                                              
 994         item.cellY = cellY;                                                                              
 995         // We store hotseat items in canonical form which is this orientation invariant position         
 996         // in the hotseat                                                                                
 997         if (context instanceof Launcher && screenId < 0 &&                                               
 998                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 999             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1000         } else {                                                                                         
1001             item.screenId = screenId;                                                                    
1002         }                                                                                                
1003                                                                                                          
1004         final ContentValues values = new ContentValues();                                                
1005         final ContentResolver cr = context.getContentResolver();                                         
1006         item.onAddToDatabase(context, values);                                                           
1007                                                                                                          
1008         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1009         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1010                                                                                                          
1011         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
1012         Runnable r = new Runnable() {                                                                    
1013             public void run() {                                                                          
1014                 cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);                               
1015                                                                                                          
1016                 // Lock on mBgLock *after* the db operation                                              
1017                 synchronized (sBgLock) {                                                                 
1018                     checkItemInfoLocked(item.id, item, stackTrace);                                      
1019                     sBgItemsIdMap.put(item.id, item);                                                    
1020                     switch (item.itemType) {                                                             
1021                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1022                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1023                             // Fall through                                                              
1024                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1025                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1026                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1027                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1028                                 sBgWorkspaceItems.add(item);                                             
1029                             } else {                                                                     
1030                                 if (!sBgFolders.containsKey(item.container)) {                           
1031                                     // Adding an item to a folder that doesn't exist.                    
1032                                     String msg = "adding item: " + item + " to a folder that " +         
1033                                             " doesn't exist";                                            
1034                                     Log.e(TAG, msg);                                                     
1035                                 }                                                                        
1036                             }                                                                            
1037                             break;                                                                       
1038                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1039                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1040                             break;                                                                       
1041                     }                                                                                    
1042                 }                                                                                        
1043             }                                                                                            
1044         };                                                                                               
1045         runOnWorkerThread(r);                                                                            
1046     }                                                                                                    
1047                                                                                                          
1048     /**                                                                                                  
1049      * Creates a new unique child id, for a given cell span across all layouts.                          
1050      */                                                                                                  
1051     static int getCellLayoutChildId(                                                                     
1052             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1053         return (((int) container & 0xFF) << 24)                                                          
1054                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1055     }                                                                                                    
1056                                                                                                          
1057     private static ArrayList<ItemInfo> getItemsByPackageName(                                            
1058             final String pn, final UserHandleCompat user) {                                              
1059         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
1060             @Override                                                                                    
1061             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1062                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1063             }                                                                                            
1064         };                                                                                               
1065         return filterItemInfos(sBgItemsIdMap, filter);                                                   
1066     }                                                                                                    
1067                                                                                                          
1068     /**                                                                                                  
1069      * Removes all the items from the database corresponding to the specified package.                   
1070      */                                                                                                  
1071     static void deletePackageFromDatabase(Context context, final String pn,                              
1072             final UserHandleCompat user) {                                                               
1073         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1074     }                                                                                                    
1075                                                                                                          
1076     /**                                                                                                  
1077      * Removes the specified item from the database                                                      
1078      * @param context                                                                                    
1079      * @param item                                                                                       
1080      */                                                                                                  
1081     public static void deleteItemFromDatabase(Context context, final ItemInfo item) {                    
1082         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1083         items.add(item);                                                                                 
1084         deleteItemsFromDatabase(context, items);                                                         
1085     }                                                                                                    
1086                                                                                                          
1087     /**                                                                                                  
1088      * Removes the specified items from the database                                                     
1089      * @param context                                                                                    
1090      * @param item                                                                                       
1091      */                                                                                                  
1092     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1093         final ContentResolver cr = context.getContentResolver();                                         
1094         Runnable r = new Runnable() {                                                                    
1095             public void run() {                                                                          
1096                 for (ItemInfo item : items) {                                                            
1097                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);                   
1098                     cr.delete(uri, null, null);                                                          
1099                                                                                                          
1100                     // Lock on mBgLock *after* the db operation                                          
1101                     synchronized (sBgLock) {                                                             
1102                         switch (item.itemType) {                                                         
1103                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
1104                                 sBgFolders.remove(item.id);                                              
1105                                 for (ItemInfo info: sBgItemsIdMap) {                                     
1106                                     if (info.container == item.id) {                                     
1107                                         // We are deleting a folder which still contains items that      
1108                                         // think they are contained by that folder.                      
1109                                         String msg = "deleting a folder (" + item + ") which still " +   
1110                                                 "contains items (" + info + ")";                         
1111                                         Log.e(TAG, msg);                                                 
1112                                     }                                                                    
1113                                 }                                                                        
1114                                 sBgWorkspaceItems.remove(item);                                          
1115                                 break;                                                                   
1116                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1117                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1118                                 sBgWorkspaceItems.remove(item);                                          
1119                                 break;                                                                   
1120                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
1121                                 sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                      
1122                                 break;                                                                   
1123                         }                                                                                
1124                         sBgItemsIdMap.remove(item.id);                                                   
1125                     }                                                                                    
1126                 }                                                                                        
1127             }                                                                                            
1128         };                                                                                               
1129         runOnWorkerThread(r);                                                                            
1130     }                                                                                                    
1131                                                                                                          
1132     /**                                                                                                  
1133      * Update the order of the workspace screens in the database. The array list contains                
1134      * a list of screen ids in the order that they should appear.                                        
1135      */                                                                                                  
1136     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1137         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1138         final ContentResolver cr = context.getContentResolver();                                         
1139         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1140                                                                                                          
1141         // Remove any negative screen ids -- these aren't persisted                                      
1142         Iterator<Long> iter = screensCopy.iterator();                                                    
1143         while (iter.hasNext()) {                                                                         
1144             long id = iter.next();                                                                       
1145             if (id < 0) {                                                                                
1146                 iter.remove();                                                                           
1147             }                                                                                            
1148         }                                                                                                
1149                                                                                                          
1150         Runnable r = new Runnable() {                                                                    
1151             @Override                                                                                    
1152             public void run() {                                                                          
1153                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1154                 // Clear the table                                                                       
1155                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1156                 int count = screensCopy.size();                                                          
1157                 for (int i = 0; i < count; i++) {                                                        
1158                     ContentValues v = new ContentValues();                                               
1159                     long screenId = screensCopy.get(i);                                                  
1160                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1161                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1162                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1163                 }                                                                                        
1164                                                                                                          
1165                 try {                                                                                    
1166                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1167                 } catch (Exception ex) {                                                                 
1168                     throw new RuntimeException(ex);                                                      
1169                 }                                                                                        
1170                                                                                                          
1171                 synchronized (sBgLock) {                                                                 
1172                     sBgWorkspaceScreens.clear();                                                         
1173                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1174                 }                                                                                        
1175             }                                                                                            
1176         };                                                                                               
1177         runOnWorkerThread(r);                                                                            
1178     }                                                                                                    
1179                                                                                                          
1180     /**                                                                                                  
1181      * Remove the contents of the specified folder from the database                                     
1182      */                                                                                                  
1183     public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {        
1184         final ContentResolver cr = context.getContentResolver();                                         
1185                                                                                                          
1186         Runnable r = new Runnable() {                                                                    
1187             public void run() {                                                                          
1188                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);                
1189                 // Lock on mBgLock *after* the db operation                                              
1190                 synchronized (sBgLock) {                                                                 
1191                     sBgItemsIdMap.remove(info.id);                                                       
1192                     sBgFolders.remove(info.id);                                                          
1193                     sBgWorkspaceItems.remove(info);                                                      
1194                 }                                                                                        
1195                                                                                                          
1196                 cr.delete(LauncherSettings.Favorites.CONTENT_URI,                                        
1197                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1198                 // Lock on mBgLock *after* the db operation                                              
1199                 synchronized (sBgLock) {                                                                 
1200                     for (ItemInfo childInfo : info.contents) {                                           
1201                         sBgItemsIdMap.remove(childInfo.id);                                              
1202                     }                                                                                    
1203                 }                                                                                        
1204             }                                                                                            
1205         };                                                                                               
1206         runOnWorkerThread(r);                                                                            
1207     }                                                                                                    
1208                                                                                                          
1209     /**                                                                                                  
1210      * Set this as the current Launcher activity object for the loader.                                  
1211      */                                                                                                  
1212     public void initialize(Callbacks callbacks) {                                                        
1213         synchronized (mLock) {                                                                           
1214             // Disconnect any of the callbacks and drawables associated with ItemInfos on the            
1215             // workspace to prevent leaking Launcher activities on orientation change.                   
1216             unbindItemInfosAndClearQueuedBindRunnables();                                                
1217             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1218         }                                                                                                
1219     }                                                                                                    
1220                                                                                                          
1221     @Override                                                                                            
1222     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1223         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1224         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1225                 user));                                                                                  
1226     }                                                                                                    
1227                                                                                                          
1228     @Override                                                                                            
1229     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1230         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1231         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1232                 user));                                                                                  
1233     }                                                                                                    
1234                                                                                                          
1235     @Override                                                                                            
1236     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1237         int op = PackageUpdatedTask.OP_ADD;                                                              
1238         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1239                 user));                                                                                  
1240     }                                                                                                    
1241                                                                                                          
1242     @Override                                                                                            
1243     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1244             boolean replacing) {                                                                         
1245         if (!replacing) {                                                                                
1246             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1247                     user));                                                                              
1248             if (mAppsCanBeOnRemoveableStorage) {                                                         
1249                 // Only rebind if we support removable storage. It catches the                           
1250                 // case where                                                                            
1251                 // apps on the external sd card need to be reloaded                                      
1252                 startLoaderFromBackground();                                                             
1253             }                                                                                            
1254         } else {                                                                                         
1255             // If we are replacing then just update the packages in the list                             
1256             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1257                     packageNames, user));                                                                
1258         }                                                                                                
1259     }                                                                                                    
1260                                                                                                          
1261     @Override                                                                                            
1262     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1263             boolean replacing) {                                                                         
1264         if (!replacing) {                                                                                
1265             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1266                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1267                     user));                                                                              
1268         }                                                                                                
1269     }                                                                                                    
1270                                                                                                          
1271     /**                                                                                                  
1272      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1273      * ACTION_PACKAGE_CHANGED.                                                                           
1274      */                                                                                                  
1275     @Override                                                                                            
1276     public void onReceive(Context context, Intent intent) {                                              
1277         if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                    
1278                                                                                                          
1279         final String action = intent.getAction();                                                        
1280         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1281             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1282             forceReload();                                                                               
1283         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1284                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1285             Callbacks callbacks = getCallback();                                                         
1286             if (callbacks != null) {                                                                     
1287                 callbacks.bindSearchablesChanged();                                                      
1288             }                                                                                            
1289         } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)                        
1290                 || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {                   
1291             forceReload();                                                                               
1292         }                                                                                                
1293     }                                                                                                    
1294                                                                                                          
1295     void forceReload() {                                                                                 
1296         resetLoadedState(true, true);                                                                    
1297                                                                                                          
1298         // Do this here because if the launcher activity is running it will be restarted.                
1299         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1300         // to reload.                                                                                    
1301         startLoaderFromBackground();                                                                     
1302     }                                                                                                    
1303                                                                                                          
1304     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1305         synchronized (mLock) {                                                                           
1306             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1307             // mWorkspaceLoaded to true later                                                            
1308             stopLoaderLocked();                                                                          
1309             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1310             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1311         }                                                                                                
1312     }                                                                                                    
1313                                                                                                          
1314     /**                                                                                                  
1315      * When the launcher is in the background, it's possible for it to miss paired                       
1316      * configuration changes.  So whenever we trigger the loader from the background                     
1317      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1318      * of doing it now.                                                                                  
1319      */                                                                                                  
1320     public void startLoaderFromBackground() {                                                            
1321         boolean runLoader = false;                                                                       
1322         Callbacks callbacks = getCallback();                                                             
1323         if (callbacks != null) {                                                                         
1324             // Only actually run the loader if they're not paused.                                       
1325             if (!callbacks.setLoadOnResume()) {                                                          
1326                 runLoader = true;                                                                        
1327             }                                                                                            
1328         }                                                                                                
1329         if (runLoader) {                                                                                 
1330             startLoader(PagedView.INVALID_RESTORE_PAGE);                                                 
1331         }                                                                                                
1332     }                                                                                                    
1333                                                                                                          
1334     /**                                                                                                  
1335      * If there is already a loader task running, tell it to stop.                                       
1336      */                                                                                                  
1337     private void stopLoaderLocked() {                                                                    
1338         LoaderTask oldTask = mLoaderTask;                                                                
1339         if (oldTask != null) {                                                                           
1340             oldTask.stopLocked();                                                                        
1341         }                                                                                                
1342     }                                                                                                    
1343                                                                                                          
1344     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1345         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1346     }                                                                                                    
1347                                                                                                          
1348     public void startLoader(int synchronousBindPage) {                                                   
1349         startLoader(synchronousBindPage, LOADER_FLAG_NONE);                                              
1350     }                                                                                                    
1351                                                                                                          
1352     public void startLoader(int synchronousBindPage, int loadFlags) {                                    
1353         // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems      
1354         InstallShortcutReceiver.enableInstallQueue();                                                    
1355         synchronized (mLock) {                                                                           
1356             // Clear any deferred bind-runnables from the synchronized load process                      
1357             // We must do this before any loading/binding is scheduled below.                            
1358             synchronized (mDeferredBindRunnables) {                                                      
1359                 mDeferredBindRunnables.clear();                                                          
1360             }                                                                                            
1361                                                                                                          
1362             // Don't bother to start the thread if we know it's not going to do anything                 
1363             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1364                 // If there is already one running, tell it to stop.                                     
1365                 stopLoaderLocked();                                                                      
1366                 mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);                              
1367                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1368                         && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {                
1369                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1370                 } else {                                                                                 
1371                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1372                     sWorker.post(mLoaderTask);                                                           
1373                 }                                                                                        
1374             }                                                                                            
1375         }                                                                                                
1376     }                                                                                                    
1377                                                                                                          
1378     void bindRemainingSynchronousPages() {                                                               
1379         // Post the remaining side pages to be loaded                                                    
1380         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1381             Runnable[] deferredBindRunnables = null;                                                     
1382             synchronized (mDeferredBindRunnables) {                                                      
1383                 deferredBindRunnables = mDeferredBindRunnables.toArray(                                  
1384                         new Runnable[mDeferredBindRunnables.size()]);                                    
1385                 mDeferredBindRunnables.clear();                                                          
1386             }                                                                                            
1387             for (final Runnable r : deferredBindRunnables) {                                             
1388                 mHandler.post(r);                                                                        
1389             }                                                                                            
1390         }                                                                                                
1391                                                                                                          
1392         // Run all the bind complete runnables after workspace is bound.                                 
1393         if (!mBindCompleteRunnables.isEmpty()) {                                                         
1394             synchronized (mBindCompleteRunnables) {                                                      
1395                 for (final Runnable r : mBindCompleteRunnables) {                                        
1396                     runOnWorkerThread(r);                                                                
1397                 }                                                                                        
1398                 mBindCompleteRunnables.clear();                                                          
1399             }                                                                                            
1400         }                                                                                                
1401     }                                                                                                    
1402                                                                                                          
1403     public void stopLoader() {                                                                           
1404         synchronized (mLock) {                                                                           
1405             if (mLoaderTask != null) {                                                                   
1406                 mLoaderTask.stopLocked();                                                                
1407             }                                                                                            
1408         }                                                                                                
1409     }                                                                                                    
1410                                                                                                          
1411     /**                                                                                                  
1412      * Loads the workspace screen ids in an ordered list.                                                
1413      */                                                                                                  
1414     @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                              
1415         final ContentResolver contentResolver = context.getContentResolver();                            
1416         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1417                                                                                                          
1418         // Get screens ordered by rank.                                                                  
1419         final Cursor sc = contentResolver.query(screensUri, null, null, null,                            
1420                 LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                          
1421         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1422         try {                                                                                            
1423             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1424             while (sc.moveToNext()) {                                                                    
1425                 try {                                                                                    
1426                     screenIds.add(sc.getLong(idIndex));                                                  
1427                 } catch (Exception e) {                                                                  
1428                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                         
1429                             + " - invalid screens: " + e, true);                                         
1430                 }                                                                                        
1431             }                                                                                            
1432         } finally {                                                                                      
1433             sc.close();                                                                                  
1434         }                                                                                                
1435         return screenIds;                                                                                
1436     }                                                                                                    
1437                                                                                                          
1438     public boolean isAllAppsLoaded() {                                                                   
1439         return mAllAppsLoaded;                                                                           
1440     }                                                                                                    
1441                                                                                                          
1442     boolean isLoadingWorkspace() {                                                                       
1443         synchronized (mLock) {                                                                           
1444             if (mLoaderTask != null) {                                                                   
1445                 return mLoaderTask.isLoadingWorkspace();                                                 
1446             }                                                                                            
1447         }                                                                                                
1448         return false;                                                                                    
1449     }                                                                                                    
1450                                                                                                          
1451     /**                                                                                                  
1452      * Runnable for the thread that loads the contents of the launcher:                                  
1453      *   - workspace icons                                                                               
1454      *   - widgets                                                                                       
1455      *   - all apps icons                                                                                
1456      */                                                                                                  
1457     private class LoaderTask implements Runnable {                                                       
1458         private Context mContext;                                                                        
1459         @Thunk boolean mIsLoadingAndBindingWorkspace;                                                    
1460         private boolean mStopped;                                                                        
1461         @Thunk boolean mLoadAndBindStepFinished;                                                         
1462         private int mFlags;                                                                              
1463                                                                                                          
1464         LoaderTask(Context context, int flags) {                                                         
1465             mContext = context;                                                                          
1466             mFlags = flags;                                                                              
1467         }                                                                                                
1468                                                                                                          
1469         boolean isLoadingWorkspace() {                                                                   
1470             return mIsLoadingAndBindingWorkspace;                                                        
1471         }                                                                                                
1472                                                                                                          
1473         private void loadAndBindWorkspace() {                                                            
1474             mIsLoadingAndBindingWorkspace = true;                                                        
1475                                                                                                          
1476             // Load the workspace                                                                        
1477             if (DEBUG_LOADERS) {                                                                         
1478                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1479             }                                                                                            
1480                                                                                                          
1481             if (!mWorkspaceLoaded) {                                                                     
1482                 loadWorkspace();                                                                         
1483                 synchronized (LoaderTask.this) {                                                         
1484                     if (mStopped) {                                                                      
1485                         return;                                                                          
1486                     }                                                                                    
1487                     mWorkspaceLoaded = true;                                                             
1488                 }                                                                                        
1489             }                                                                                            
1490                                                                                                          
1491             // Bind the workspace                                                                        
1492             bindWorkspace(-1);                                                                           
1493         }                                                                                                
1494                                                                                                          
1495         private void waitForIdle() {                                                                     
1496             // Wait until the either we're stopped or the other threads are done.                        
1497             // This way we don't start loading all apps until the workspace has settled                  
1498             // down.                                                                                     
1499             synchronized (LoaderTask.this) {                                                             
1500                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1501                                                                                                          
1502                 mHandler.postIdle(new Runnable() {                                                       
1503                         public void run() {                                                              
1504                             synchronized (LoaderTask.this) {                                             
1505                                 mLoadAndBindStepFinished = true;                                         
1506                                 if (DEBUG_LOADERS) {                                                     
1507                                     Log.d(TAG, "done with previous binding step");                       
1508                                 }                                                                        
1509                                 LoaderTask.this.notify();                                                
1510                             }                                                                            
1511                         }                                                                                
1512                     });                                                                                  
1513                                                                                                          
1514                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1515                     try {                                                                                
1516                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1517                         // wait no longer than 1sec at a time                                            
1518                         this.wait(1000);                                                                 
1519                     } catch (InterruptedException ex) {                                                  
1520                         // Ignore                                                                        
1521                     }                                                                                    
1522                 }                                                                                        
1523                 if (DEBUG_LOADERS) {                                                                     
1524                     Log.d(TAG, "waited "                                                                 
1525                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1526                             + "ms for previous step to finish binding");                                 
1527                 }                                                                                        
1528             }                                                                                            
1529         }                                                                                                
1530                                                                                                          
1531         void runBindSynchronousPage(int synchronousBindPage) {                                           
1532             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1533                 // Ensure that we have a valid page index to load synchronously                          
1534                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1535                         "valid page index");                                                             
1536             }                                                                                            
1537             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1538                 // Ensure that we don't try and bind a specified page when the pages have not been       
1539                 // loaded already (we should load everything asynchronously in that case)                
1540                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1541             }                                                                                            
1542             synchronized (mLock) {                                                                       
1543                 if (mIsLoaderTaskRunning) {                                                              
1544                     // Ensure that we are never running the background loading at this point since       
1545                     // we also touch the background collections                                          
1546                     throw new RuntimeException("Error! Background loading is already running");          
1547                 }                                                                                        
1548             }                                                                                            
1549                                                                                                          
1550             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1551             //      data structures, we can't allow any other thread to touch that data, but because     
1552             //      this call is synchronous, we can get away with not locking).                         
1553                                                                                                          
1554             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1555             // operations from the previous activity.  We need to ensure that all queued operations      
1556             // are executed before any synchronous binding work is done.                                 
1557             mHandler.flush();                                                                            
1558                                                                                                          
1559             // Divide the set of loaded items into those that we are binding synchronously, and          
1560             // everything else that is to be bound normally (asynchronously).                            
1561             bindWorkspace(synchronousBindPage);                                                          
1562             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1563             //      arise from that.                                                                     
1564             onlyBindAllApps();                                                                           
1565         }                                                                                                
1566                                                                                                          
1567         public void run() {                                                                              
1568             synchronized (mLock) {                                                                       
1569                 if (mStopped) {                                                                          
1570                     return;                                                                              
1571                 }                                                                                        
1572                 mIsLoaderTaskRunning = true;                                                             
1573             }                                                                                            
1574             // Optimize for end-user experience: if the Launcher is up and // running with the           
1575             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1576             // workspace first (default).                                                                
1577             keep_running: {                                                                              
1578                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1579                 loadAndBindWorkspace();                                                                  
1580                                                                                                          
1581                 if (mStopped) {                                                                          
1582                     break keep_running;                                                                  
1583                 }                                                                                        
1584                                                                                                          
1585                 waitForIdle();                                                                           
1586                                                                                                          
1587                 // second step                                                                           
1588                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1589                 loadAndBindAllApps();                                                                    
1590             }                                                                                            
1591                                                                                                          
1592             // Clear out this reference, otherwise we end up holding it until all of the                 
1593             // callback runnables are done.                                                              
1594             mContext = null;                                                                             
1595                                                                                                          
1596             synchronized (mLock) {                                                                       
1597                 // If we are still the last one to be scheduled, remove ourselves.                       
1598                 if (mLoaderTask == this) {                                                               
1599                     mLoaderTask = null;                                                                  
1600                 }                                                                                        
1601                 mIsLoaderTaskRunning = false;                                                            
1602                 mHasLoaderCompletedOnce = true;                                                          
1603             }                                                                                            
1604         }                                                                                                
1605                                                                                                          
1606         public void stopLocked() {                                                                       
1607             synchronized (LoaderTask.this) {                                                             
1608                 mStopped = true;                                                                         
1609                 this.notify();                                                                           
1610             }                                                                                            
1611         }                                                                                                
1612                                                                                                          
1613         /**                                                                                              
1614          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1615          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1616          * object that was around when the deferred message was scheduled, and if there's                
1617          * a new Callbacks object around then also return null.  This will save us from                  
1618          * calling onto it with data that will be ignored.                                               
1619          */                                                                                              
1620         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1621             synchronized (mLock) {                                                                       
1622                 if (mStopped) {                                                                          
1623                     return null;                                                                         
1624                 }                                                                                        
1625                                                                                                          
1626                 if (mCallbacks == null) {                                                                
1627                     return null;                                                                         
1628                 }                                                                                        
1629                                                                                                          
1630                 final Callbacks callbacks = mCallbacks.get();                                            
1631                 if (callbacks != oldCallbacks) {                                                         
1632                     return null;                                                                         
1633                 }                                                                                        
1634                 if (callbacks == null) {                                                                 
1635                     Log.w(TAG, "no mCallbacks");                                                         
1636                     return null;                                                                         
1637                 }                                                                                        
1638                                                                                                          
1639                 return callbacks;                                                                        
1640             }                                                                                            
1641         }                                                                                                
1642                                                                                                          
1643         // check & update map of what's occupied; used to discard overlapping/invalid items              
1644         private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {         
1645             LauncherAppState app = LauncherAppState.getInstance();                                       
1646             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1647             final int countX = (int) profile.numColumns;                                                 
1648             final int countY = (int) profile.numRows;                                                    
1649                                                                                                          
1650             long containerIndex = item.screenId;                                                         
1651             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1652                 // Return early if we detect that an item is under the hotseat button                    
1653                 if (mCallbacks == null ||                                                                
1654                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1655                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1656                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1657                             + item.cellY + ") occupied by all apps");                                    
1658                     return false;                                                                        
1659                 }                                                                                        
1660                                                                                                          
1661                 final ItemInfo[][] hotseatItems =                                                        
1662                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1663                                                                                                          
1664                 if (item.screenId >= profile.numHotseatIcons) {                                          
1665                     Log.e(TAG, "Error loading shortcut " + item                                          
1666                             + " into hotseat position " + item.screenId                                  
1667                             + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1)         
1668                             + ")");                                                                      
1669                     return false;                                                                        
1670                 }                                                                                        
1671                                                                                                          
1672                 if (hotseatItems != null) {                                                              
1673                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1674                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1675                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1676                                 + item.cellY + ") occupied by "                                          
1677                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1678                                 [(int) item.screenId][0]);                                               
1679                             return false;                                                                
1680                     } else {                                                                             
1681                         hotseatItems[(int) item.screenId][0] = item;                                     
1682                         return true;                                                                     
1683                     }                                                                                    
1684                 } else {                                                                                 
1685                     final ItemInfo[][] items = new ItemInfo[(int) profile.numHotseatIcons][1];           
1686                     items[(int) item.screenId][0] = item;                                                
1687                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1688                     return true;                                                                         
1689                 }                                                                                        
1690             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1691                 // Skip further checking if it is not the hotseat or workspace container                 
1692                 return true;                                                                             
1693             }                                                                                            
1694                                                                                                          
1695             if (!occupied.containsKey(item.screenId)) {                                                  
1696                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1697                 occupied.put(item.screenId, items);                                                      
1698             }                                                                                            
1699                                                                                                          
1700             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1701             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1702                     item.cellX < 0 || item.cellY < 0 ||                                                  
1703                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1704                 Log.e(TAG, "Error loading shortcut " + item                                              
1705                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1706                         + item.cellX + "," + item.cellY                                                  
1707                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1708                 return false;                                                                            
1709             }                                                                                            
1710                                                                                                          
1711             // Check if any workspace icons overlap with each other                                      
1712             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1713                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1714                     if (screens[x][y] != null) {                                                         
1715                         Log.e(TAG, "Error loading shortcut " + item                                      
1716                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1717                             + x + "," + y                                                                
1718                             + ") occupied by "                                                           
1719                             + screens[x][y]);                                                            
1720                         return false;                                                                    
1721                     }                                                                                    
1722                 }                                                                                        
1723             }                                                                                            
1724             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1725                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1726                     screens[x][y] = item;                                                                
1727                 }                                                                                        
1728             }                                                                                            
1729                                                                                                          
1730             return true;                                                                                 
1731         }                                                                                                
1732                                                                                                          
1733         /** Clears all the sBg data structures */                                                        
1734         private void clearSBgDataStructures() {                                                          
1735             synchronized (sBgLock) {                                                                     
1736                 sBgWorkspaceItems.clear();                                                               
1737                 sBgAppWidgets.clear();                                                                   
1738                 sBgFolders.clear();                                                                      
1739                 sBgItemsIdMap.clear();                                                                   
1740                 sBgWorkspaceScreens.clear();                                                             
1741             }                                                                                            
1742         }                                                                                                
1743                                                                                                          
1744         private void loadWorkspace() {                                                                   
1745             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
1746                                                                                                          
1747             final Context context = mContext;                                                            
1748             final ContentResolver contentResolver = context.getContentResolver();                        
1749             final PackageManager manager = context.getPackageManager();                                  
1750             final boolean isSafeMode = manager.isSafeMode();                                             
1751             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1752             final boolean isSdCardReady = context.registerReceiver(null,                                 
1753                     new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                             
1754                                                                                                          
1755             LauncherAppState app = LauncherAppState.getInstance();                                       
1756             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1757             int countX = (int) profile.numColumns;                                                       
1758             int countY = (int) profile.numRows;                                                          
1759                                                                                                          
1760             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1761                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1762                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1763             }                                                                                            
1764                                                                                                          
1765             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1766                 // append the user's Launcher2 shortcuts                                                 
1767                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1768                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1769             } else {                                                                                     
1770                 // Make sure the default workspace is loaded                                             
1771                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1772                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1773             }                                                                                            
1774                                                                                                          
1775             synchronized (sBgLock) {                                                                     
1776                 clearSBgDataStructures();                                                                
1777                 final HashMap<String, Integer> installingPkgs = PackageInstallerCompat                   
1778                         .getInstance(mContext).updateAndGetActiveSessionCache();                         
1779                                                                                                          
1780                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1781                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1782                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
1783                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
1784                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1785                                                                                                          
1786                 // +1 for the hotseat (it can be larger than the workspace)                              
1787                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1788                 // before any earlier duplicates)                                                        
1789                 final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();                        
1790                                                                                                          
1791                 try {                                                                                    
1792                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1793                     final int intentIndex = c.getColumnIndexOrThrow                                      
1794                             (LauncherSettings.Favorites.INTENT);                                         
1795                     final int titleIndex = c.getColumnIndexOrThrow                                       
1796                             (LauncherSettings.Favorites.TITLE);                                          
1797                     final int containerIndex = c.getColumnIndexOrThrow(                                  
1798                             LauncherSettings.Favorites.CONTAINER);                                       
1799                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
1800                             LauncherSettings.Favorites.ITEM_TYPE);                                       
1801                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
1802                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
1803                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
1804                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
1805                     final int screenIndex = c.getColumnIndexOrThrow(                                     
1806                             LauncherSettings.Favorites.SCREEN);                                          
1807                     final int cellXIndex = c.getColumnIndexOrThrow                                       
1808                             (LauncherSettings.Favorites.CELLX);                                          
1809                     final int cellYIndex = c.getColumnIndexOrThrow                                       
1810                             (LauncherSettings.Favorites.CELLY);                                          
1811                     final int spanXIndex = c.getColumnIndexOrThrow                                       
1812                             (LauncherSettings.Favorites.SPANX);                                          
1813                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
1814                             LauncherSettings.Favorites.SPANY);                                           
1815                     final int rankIndex = c.getColumnIndexOrThrow(                                       
1816                             LauncherSettings.Favorites.RANK);                                            
1817                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
1818                             LauncherSettings.Favorites.RESTORED);                                        
1819                     final int profileIdIndex = c.getColumnIndexOrThrow(                                  
1820                             LauncherSettings.Favorites.PROFILE_ID);                                      
1821                     final int optionsIndex = c.getColumnIndexOrThrow(                                    
1822                             LauncherSettings.Favorites.OPTIONS);                                         
1823                     final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);                         
1824                                                                                                          
1825                     final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();          
1826                     for (UserHandleCompat user : mUserManager.getUserProfiles()) {                       
1827                         allUsers.put(mUserManager.getSerialNumberForUser(user), user);                   
1828                     }                                                                                    
1829                                                                                                          
1830                     ShortcutInfo info;                                                                   
1831                     String intentDescription;                                                            
1832                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1833                     int container;                                                                       
1834                     long id;                                                                             
1835                     long serialNumber;                                                                   
1836                     Intent intent;                                                                       
1837                     UserHandleCompat user;                                                               
1838                                                                                                          
1839                     while (!mStopped && c.moveToNext()) {                                                
1840                         try {                                                                            
1841                             int itemType = c.getInt(itemTypeIndex);                                      
1842                             boolean restored = 0 != c.getInt(restoredIndex);                             
1843                             boolean allowMissingTarget = false;                                          
1844                             container = c.getInt(containerIndex);                                        
1845                                                                                                          
1846                             switch (itemType) {                                                          
1847                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1848                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1849                                 id = c.getLong(idIndex);                                                 
1850                                 intentDescription = c.getString(intentIndex);                            
1851                                 serialNumber = c.getInt(profileIdIndex);                                 
1852                                 user = allUsers.get(serialNumber);                                       
1853                                 int promiseType = c.getInt(restoredIndex);                               
1854                                 int disabledState = 0;                                                   
1855                                 boolean itemReplaced = false;                                            
1856                                 if (user == null) {                                                      
1857                                     // User has been deleted remove the item.                            
1858                                     itemsToRemove.add(id);                                               
1859                                     continue;                                                            
1860                                 }                                                                        
1861                                 try {                                                                    
1862                                     intent = Intent.parseUri(intentDescription, 0);                      
1863                                     ComponentName cn = intent.getComponent();                            
1864                                     if (cn != null && cn.getPackageName() != null) {                     
1865                                         boolean validPkg = launcherApps.isPackageEnabledForProfile(      
1866                                                 cn.getPackageName(), user);                              
1867                                         boolean validComponent = validPkg &&                             
1868                                                 launcherApps.isActivityEnabledForProfile(cn, user);      
1869                                                                                                          
1870                                         if (validComponent) {                                            
1871                                             if (restored) {                                              
1872                                                 // no special handling necessary for this item           
1873                                                 restoredRows.add(id);                                    
1874                                                 restored = false;                                        
1875                                             }                                                            
1876                                         } else if (validPkg) {                                           
1877                                             intent = null;                                               
1878                                             if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
1879                                                 // We allow auto install apps to have their intent       
1880                                                 // updated after an install.                             
1881                                                 intent = manager.getLaunchIntentForPackage(              
1882                                                         cn.getPackageName());                            
1883                                                 if (intent != null) {                                    
1884                                                     ContentValues values = new ContentValues();          
1885                                                     values.put(LauncherSettings.Favorites.INTENT,        
1886                                                             intent.toUri(0));                            
1887                                                     updateItem(id, values);                              
1888                                                 }                                                        
1889                                             }                                                            
1890                                                                                                          
1891                                             if (intent == null) {                                        
1892                                                 // The app is installed but the component is no          
1893                                                 // longer available.                                     
1894                                                 Launcher.addDumpLog(TAG,                                 
1895                                                         "Invalid component removed: " + cn, true);       
1896                                                 itemsToRemove.add(id);                                   
1897                                                 continue;                                                
1898                                             } else {                                                     
1899                                                 // no special handling necessary for this item           
1900                                                 restoredRows.add(id);                                    
1901                                                 restored = false;                                        
1902                                             }                                                            
1903                                         } else if (restored) {                                           
1904                                             // Package is not yet available but might be                 
1905                                             // installed later.                                          
1906                                             Launcher.addDumpLog(TAG,                                     
1907                                                     "package not yet restored: " + cn, true);            
1908                                                                                                          
1909                                             if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
1910                                                 // Restore has started once.                             
1911                                             } else if (installingPkgs.containsKey(cn.getPackageName())) {
1912                                                 // App restore has started. Update the flag              
1913                                                 promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;        
1914                                                 ContentValues values = new ContentValues();              
1915                                                 values.put(LauncherSettings.Favorites.RESTORED,          
1916                                                         promiseType);                                    
1917                                                 updateItem(id, values);                                  
1918                                             } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE🔵
1919                                                 // This is a common app. Try to replace this.            
1920                                                 int appType = CommonAppTypeParser.decodeItemTypeFromFlag(🔵
1921                                                 CommonAppTypeParser parser = new CommonAppTypeParser(id, 🔵
1922                                                 if (parser.findDefaultApp()) {                           
1923                                                     // Default app found. Replace it.                    
1924                                                     intent = parser.parsedIntent;                        
1925                                                     cn = intent.getComponent();                          
1926                                                     ContentValues values = parser.parsedValues;          
1927                                                     values.put(LauncherSettings.Favorites.RESTORED, 0);  
1928                                                     updateItem(id, values);                              
1929                                                     restored = false;                                    
1930                                                     itemReplaced = true;                                 
1931                                                                                                          
1932                                                 } else if (REMOVE_UNRESTORED_ICONS) {                    
1933                                                     Launcher.addDumpLog(TAG,                             
1934                                                             "Unrestored package removed: " + cn, true);  
1935                                                     itemsToRemove.add(id);                               
1936                                                     continue;                                            
1937                                                 }                                                        
1938                                             } else if (REMOVE_UNRESTORED_ICONS) {                        
1939                                                 Launcher.addDumpLog(TAG,                                 
1940                                                         "Unrestored package removed: " + cn, true);      
1941                                                 itemsToRemove.add(id);                                   
1942                                                 continue;                                                
1943                                             }                                                            
1944                                         } else if (launcherApps.isAppEnabled(                            
1945                                                 manager, cn.getPackageName(),                            
1946                                                 PackageManager.GET_UNINSTALLED_PACKAGES)) {              
1947                                             // Package is present but not available.                     
1948                                             allowMissingTarget = true;                                   
1949                                             disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;    
1950                                         } else if (!isSdCardReady) {                                     
1951                                             // SdCard is not ready yet. Package might get available,     
1952                                             // once it is ready.                                         
1953                                             Launcher.addDumpLog(TAG, "Invalid package: " + cn            
1954                                                     + " (check again later)", true);                     
1955                                             HashSet<String> pkgs = sPendingPackages.get(user);           
1956                                             if (pkgs == null) {                                          
1957                                                 pkgs = new HashSet<String>();                            
1958                                                 sPendingPackages.put(user, pkgs);                        
1959                                             }                                                            
1960                                             pkgs.add(cn.getPackageName());                               
1961                                             allowMissingTarget = true;                                   
1962                                             // Add the icon on the workspace anyway.                     
1963                                                                                                          
1964                                         } else {                                                         
1965                                             // Do not wait for external media load anymore.              
1966                                             // Log the invalid package, and remove it                    
1967                                             Launcher.addDumpLog(TAG,                                     
1968                                                     "Invalid package removed: " + cn, true);             
1969                                             itemsToRemove.add(id);                                       
1970                                             continue;                                                    
1971                                         }                                                                
1972                                     } else if (cn == null) {                                             
1973                                         // For shortcuts with no component, keep them as they are        
1974                                         restoredRows.add(id);                                            
1975                                         restored = false;                                                
1976                                     }                                                                    
1977                                 } catch (URISyntaxException e) {                                         
1978                                     Launcher.addDumpLog(TAG,                                             
1979                                             "Invalid uri: " + intentDescription, true);                  
1980                                     continue;                                                            
1981                                 }                                                                        
1982                                                                                                          
1983                                 boolean useLowResIcon = container >= 0 &&                                
1984                                         c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;          
1985                                                                                                          
1986                                 if (itemReplaced) {                                                      
1987                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
1988                                         info = getAppShortcutInfo(manager, intent, user, context, null,  
1989                                                 cursorIconInfo.iconIndex, titleIndex,                    
1990                                                 false, useLowResIcon);                                   
1991                                     } else {                                                             
1992                                         // Don't replace items for other profiles.                       
1993                                         itemsToRemove.add(id);                                           
1994                                         continue;                                                        
1995                                     }                                                                    
1996                                 } else if (restored) {                                                   
1997                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
1998                                         Launcher.addDumpLog(TAG,                                         
1999                                                 "constructing info for partially restored package",      
2000                                                 true);                                                   
2001                                         info = getRestoredItemInfo(c, titleIndex, intent,                
2002                                                 promiseType, itemType, cursorIconInfo, context);         
2003                                         intent = getRestoredItemIntent(c, context, intent);              
2004                                     } else {                                                             
2005                                         // Don't restore items for other profiles.                       
2006                                         itemsToRemove.add(id);                                           
2007                                         continue;                                                        
2008                                     }                                                                    
2009                                 } else if (itemType ==                                                   
2010                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
2011                                     info = getAppShortcutInfo(manager, intent, user, context, c,         
2012                                             cursorIconInfo.iconIndex, titleIndex,                        
2013                                             allowMissingTarget, useLowResIcon);                          
2014                                 } else {                                                                 
2015                                     info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);      
2016                                                                                                          
2017                                     // App shortcuts that used to be automatically added to Launcher     
2018                                     // didn't always have the correct intent flags set, so do that       
2019                                     // here                                                              
2020                                     if (intent.getAction() != null &&                                    
2021                                         intent.getCategories() != null &&                                
2022                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
2023                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
2024                                         intent.addFlags(                                                 
2025                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
2026                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2027                                     }                                                                    
2028                                 }                                                                        
2029                                                                                                          
2030                                 if (info != null) {                                                      
2031                                     info.id = id;                                                        
2032                                     info.intent = intent;                                                
2033                                     info.container = container;                                          
2034                                     info.screenId = c.getInt(screenIndex);                               
2035                                     info.cellX = c.getInt(cellXIndex);                                   
2036                                     info.cellY = c.getInt(cellYIndex);                                   
2037                                     info.rank = c.getInt(rankIndex);                                     
2038                                     info.spanX = 1;                                                      
2039                                     info.spanY = 1;                                                      
2040                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);          
2041                                     if (info.promisedIntent != null) {                                   
2042                                         info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber🔵
2043                                     }                                                                    
2044                                     info.isDisabled = disabledState;                                     
2045                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {         
2046                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;          
2047                                     }                                                                    
2048                                                                                                          
2049                                     // check & update map of what's occupied                             
2050                                     if (!checkItemPlacement(occupied, info)) {                           
2051                                         itemsToRemove.add(id);                                           
2052                                         break;                                                           
2053                                     }                                                                    
2054                                                                                                          
2055                                     if (restored) {                                                      
2056                                         ComponentName cn = info.getTargetComponent();                    
2057                                         if (cn != null) {                                                
2058                                             Integer progress = installingPkgs.get(cn.getPackageName());  
2059                                             if (progress != null) {                                      
2060                                                 info.setInstallProgress(progress);                       
2061                                             } else {                                                     
2062                                                 info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
2063                                             }                                                            
2064                                         }                                                                
2065                                     }                                                                    
2066                                                                                                          
2067                                     switch (container) {                                                 
2068                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2069                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2070                                         sBgWorkspaceItems.add(info);                                     
2071                                         break;                                                           
2072                                     default:                                                             
2073                                         // Item is in a user folder                                      
2074                                         FolderInfo folderInfo =                                          
2075                                                 findOrMakeFolder(sBgFolders, container);                 
2076                                         folderInfo.add(info);                                            
2077                                         break;                                                           
2078                                     }                                                                    
2079                                     sBgItemsIdMap.put(info.id, info);                                    
2080                                 } else {                                                                 
2081                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2082                                 }                                                                        
2083                                 break;                                                                   
2084                                                                                                          
2085                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2086                                 id = c.getLong(idIndex);                                                 
2087                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2088                                                                                                          
2089                                 // Do not trim the folder label, as is was set by the user.              
2090                                 folderInfo.title = c.getString(titleIndex);                              
2091                                 folderInfo.id = id;                                                      
2092                                 folderInfo.container = container;                                        
2093                                 folderInfo.screenId = c.getInt(screenIndex);                             
2094                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2095                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2096                                 folderInfo.spanX = 1;                                                    
2097                                 folderInfo.spanY = 1;                                                    
2098                                 folderInfo.options = c.getInt(optionsIndex);                             
2099                                                                                                          
2100                                 // check & update map of what's occupied                                 
2101                                 if (!checkItemPlacement(occupied, folderInfo)) {                         
2102                                     itemsToRemove.add(id);                                               
2103                                     break;                                                               
2104                                 }                                                                        
2105                                                                                                          
2106                                 switch (container) {                                                     
2107                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2108                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2109                                         sBgWorkspaceItems.add(folderInfo);                               
2110                                         break;                                                           
2111                                 }                                                                        
2112                                                                                                          
2113                                 if (restored) {                                                          
2114                                     // no special handling required for restored folders                 
2115                                     restoredRows.add(id);                                                
2116                                 }                                                                        
2117                                                                                                          
2118                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2119                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2120                                 break;                                                                   
2121                                                                                                          
2122                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2123                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
2124                                 // Read all Launcher-specific widget details                             
2125                                 boolean customWidget = itemType ==                                       
2126                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
2127                                                                                                          
2128                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2129 <<<<<<< GitAnalyzerPlus_ours                                                                             
2130                                 serialNumber = c.getLong(profileIdIndex);                                
2131 ||||||| GitAnalyzerPlus_base                                                                             
2132                                 if (info != null) {                                                      
2133                                     info.id = id;                                                        
2134                                     info.intent = intent;                                                
2135                                     container = c.getInt(containerIndex);                                
2136                                     info.container = container;                                          
2137                                     info.screenId = c.getInt(screenIndex);                               
2138                                     info.cellX = c.getInt(cellXIndex);                                   
2139                                     info.cellY = c.getInt(cellYIndex);                                   
2140                                     info.rank = c.getInt(rankIndex);                                     
2141                                     info.spanX = 1;                                                      
2142                                     info.spanY = 1;                                                      
2143                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);          
2144                                     info.isDisabled = disabledState;                                     
2145                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {         
2146                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;          
2147                                     }                                                                    
2148                                                                                                          
2149                                     // check & update map of what's occupied                             
2150                                     if (!checkItemPlacement(occupied, info)) {                           
2151                                         itemsToRemove.add(id);                                           
2152                                         break;                                                           
2153                                     }                                                                    
2154                                                                                                          
2155                                     switch (container) {                                                 
2156                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2157                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2158                                         sBgWorkspaceItems.add(info);                                     
2159                                         break;                                                           
2160                                     default:                                                             
2161                                         // Item is in a user folder                                      
2162                                         FolderInfo folderInfo =                                          
2163                                                 findOrMakeFolder(sBgFolders, container);                 
2164                                         folderInfo.add(info);                                            
2165                                         break;                                                           
2166                                     }                                                                    
2167                                     sBgItemsIdMap.put(info.id, info);                                    
2168                                                                                                          
2169                                     // now that we've loaded everthing re-save it with the               
2170                                     // icon in case it disappears somehow.                               
2171                                     queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);            
2172                                 } else {                                                                 
2173                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2174                                 }                                                                        
2175                                 break;                                                                   
2176                                                                                                          
2177                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2178                                 id = c.getLong(idIndex);                                                 
2179                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2180                                                                                                          
2181                                 folderInfo.title = c.getString(titleIndex);                              
2182                                 folderInfo.id = id;                                                      
2183                                 container = c.getInt(containerIndex);                                    
2184                                 folderInfo.container = container;                                        
2185                                 folderInfo.screenId = c.getInt(screenIndex);                             
2186                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2187                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2188                                 folderInfo.spanX = 1;                                                    
2189                                 folderInfo.spanY = 1;                                                    
2190                                                                                                          
2191                                 // check & update map of what's occupied                                 
2192                                 if (!checkItemPlacement(occupied, folderInfo)) {                         
2193                                     itemsToRemove.add(id);                                               
2194                                     break;                                                               
2195                                 }                                                                        
2196                                                                                                          
2197                                 switch (container) {                                                     
2198                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2199                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2200                                         sBgWorkspaceItems.add(folderInfo);                               
2201                                         break;                                                           
2202                                 }                                                                        
2203                                                                                                          
2204                                 if (restored) {                                                          
2205                                     // no special handling required for restored folders                 
2206                                     restoredRows.add(id);                                                
2207                                 }                                                                        
2208                                                                                                          
2209                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2210                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2211                                 break;                                                                   
2212                                                                                                          
2213                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2214                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
2215                                 // Read all Launcher-specific widget details                             
2216                                 boolean customWidget = itemType ==                                       
2217                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
2218                                                                                                          
2219                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2220                                 serialNumber= c.getLong(profileIdIndex);                                 
2221                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2222                                 id = c.getLong(idIndex);                                                 
2223                                 final ComponentName component =                                          
2224                                         ComponentName.unflattenFromString(savedProvider);                
2225                                                                                                          
2226                                 final int restoreStatus = c.getInt(restoredIndex);                       
2227 =======                                                                                                  
2228                                 serialNumber= c.getLong(profileIdIndex);                                 
2229                                 user = mUserManager.getUserForSerialNumber(serialNumber);                
2230                                 if (user == null) {                                                      
2231                                     // User has been deleted remove the item.                            
2232                                     itemsToRemove.add(id);                                               
2233                                     continue;                                                            
2234                                 }                                                                        
2235 >>>>>>> GitAnalyzerPlus_theirs                                                                           
2236                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2237                                 id = c.getLong(idIndex);                                                 
2238                                 user = allUsers.get(serialNumber);                                       
2239                                 if (user == null) {                                                      
2240                                     itemsToRemove.add(id);                                               
2241                                     continue;                                                            
2242                                 }                                                                        
2243                                                                                                          
2244                                 final ComponentName component =                                          
2245                                         ComponentName.unflattenFromString(savedProvider);                
2246                                                                                                          
2247                                 final int restoreStatus = c.getInt(restoredIndex);                       
2248                                 final boolean isIdValid = (restoreStatus &                               
2249                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                   
2250                                 final boolean wasProviderReady = (restoreStatus &                        
2251                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;             
2252                                                                                                          
2253                                 final LauncherAppWidgetProviderInfo provider =                           
2254                                         LauncherModel.getProviderInfo(context,                           
2255                                                 ComponentName.unflattenFromString(savedProvider),        
2256                                                 user);                                                   
2257                                                                                                          
2258                                 final boolean isProviderReady = isValidProvider(provider);               
2259                                 if (!isSafeMode && !customWidget &&                                      
2260                                         wasProviderReady && !isProviderReady) {                          
2261                                     String log = "Deleting widget that isn't installed anymore: "        
2262                                             + "id=" + id + " appWidgetId=" + appWidgetId;                
2263                                                                                                          
2264                                     Log.e(TAG, log);                                                     
2265                                     Launcher.addDumpLog(TAG, log, false);                                
2266                                     itemsToRemove.add(id);                                               
2267                                 } else {                                                                 
2268                                     if (isProviderReady) {                                               
2269                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2270                                                 provider.provider);                                      
2271                                                                                                          
2272                                         int status = restoreStatus;                                      
2273                                         if (!wasProviderReady) {                                         
2274                                             // If provider was not previously ready, update the          
2275                                             // status and UI flag.                                       
2276                                                                                                          
2277                                             // Id would be valid only if the widget restore broadcast was🔵
2278                                             if (isIdValid) {                                             
2279                                                 status = LauncherAppWidgetInfo.RESTORE_COMPLETED;        
2280                                             } else {                                                     
2281                                                 status &= ~LauncherAppWidgetInfo                         
2282                                                         .FLAG_PROVIDER_NOT_READY;                        
2283                                             }                                                            
2284                                         }                                                                
2285                                         appWidgetInfo.restoreStatus = status;                            
2286                                     } else {                                                             
2287                                         Log.v(TAG, "Widget restore pending id=" + id                     
2288                                                 + " appWidgetId=" + appWidgetId                          
2289                                                 + " status =" + restoreStatus);                          
2290                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2291                                                 component);                                              
2292                                         appWidgetInfo.restoreStatus = restoreStatus;                     
2293                                         Integer installProgress = installingPkgs.get(component.getPackage🔵
2294                                                                                                          
2295                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) 🔵
2296                                             // Restore has started once.                                 
2297                                         } else if (installProgress != null) {                            
2298                                             // App restore has started. Update the flag                  
2299                                             appWidgetInfo.restoreStatus |=                               
2300                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;          
2301                                         } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {             
2302                                             Launcher.addDumpLog(TAG,                                     
2303                                                     "Unrestored widget removed: " + component, true);    
2304                                             itemsToRemove.add(id);                                       
2305                                             continue;                                                    
2306                                         }                                                                
2307                                                                                                          
2308                                         appWidgetInfo.installProgress =                                  
2309                                                 installProgress == null ? 0 : installProgress;           
2310                                     }                                                                    
2311                                                                                                          
2312                                     appWidgetInfo.id = id;                                               
2313                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2314                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2315                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2316                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2317                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2318                                     appWidgetInfo.user = user;                                           
2319                                                                                                          
2320                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2321                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2322                                         Log.e(TAG, "Widget found where container != " +                  
2323                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2324                                         continue;                                                        
2325                                     }                                                                    
2326                                                                                                          
2327                                     appWidgetInfo.container = container;                                 
2328                                     // check & update map of what's occupied                             
2329                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {                  
2330                                         itemsToRemove.add(id);                                           
2331                                         break;                                                           
2332                                     }                                                                    
2333                                                                                                          
2334                                     if (!customWidget) {                                                 
2335                                         String providerName =                                            
2336                                                 appWidgetInfo.providerName.flattenToString();            
2337                                         if (!providerName.equals(savedProvider) ||                       
2338                                                 (appWidgetInfo.restoreStatus != restoreStatus)) {        
2339                                             ContentValues values = new ContentValues();                  
2340                                             values.put(                                                  
2341                                                     LauncherSettings.Favorites.APPWIDGET_PROVIDER,       
2342                                                     providerName);                                       
2343                                             values.put(LauncherSettings.Favorites.RESTORED,              
2344                                                     appWidgetInfo.restoreStatus);                        
2345                                             updateItem(id, values);                                      
2346                                         }                                                                
2347                                     }                                                                    
2348                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2349                                     sBgAppWidgets.add(appWidgetInfo);                                    
2350                                 }                                                                        
2351                                 break;                                                                   
2352                             }                                                                            
2353                         } catch (Exception e) {                                                          
2354                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2355                         }                                                                                
2356                     }                                                                                    
2357                 } finally {                                                                              
2358                     if (c != null) {                                                                     
2359                         c.close();                                                                       
2360                     }                                                                                    
2361                 }                                                                                        
2362                                                                                                          
2363                 // Break early if we've stopped loading                                                  
2364                 if (mStopped) {                                                                          
2365                     clearSBgDataStructures();                                                            
2366                     return;                                                                              
2367                 }                                                                                        
2368                                                                                                          
2369                 if (itemsToRemove.size() > 0) {                                                          
2370                     // Remove dead items                                                                 
2371                     contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI,                       
2372                             Utilities.createDbSelectionQuery(                                            
2373                                     LauncherSettings.Favorites._ID, itemsToRemove), null);               
2374                     if (DEBUG_LOADERS) {                                                                 
2375                         Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(                      
2376                                 LauncherSettings.Favorites._ID, itemsToRemove));                         
2377                     }                                                                                    
2378                                                                                                          
2379                     // Remove any empty folder                                                           
2380                     for (long folderId : LauncherAppState.getLauncherProvider()                          
2381                             .deleteEmptyFolders()) {                                                     
2382                         sBgWorkspaceItems.remove(sBgFolders.get(folderId));                              
2383                         sBgFolders.remove(folderId);                                                     
2384                         sBgItemsIdMap.remove(folderId);                                                  
2385                     }                                                                                    
2386                 }                                                                                        
2387                                                                                                          
2388                 if (restoredRows.size() > 0) {                                                           
2389                     // Update restored items that no longer require special handling                     
2390                     ContentValues values = new ContentValues();                                          
2391                     values.put(LauncherSettings.Favorites.RESTORED, 0);                                  
2392                     contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values,               
2393                             Utilities.createDbSelectionQuery(                                            
2394                                     LauncherSettings.Favorites._ID, restoredRows), null);                
2395                 }                                                                                        
2396                                                                                                          
2397                 if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                     
2398                     context.registerReceiver(new AppsAvailabilityCheck(),                                
2399                             new IntentFilter(StartupReceiver.SYSTEM_READY),                              
2400                             null, sWorker);                                                              
2401                 }                                                                                        
2402                                                                                                          
2403                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2404                                                                                                          
2405                 // Remove any empty screens                                                              
2406                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                
2407                 for (ItemInfo item: sBgItemsIdMap) {                                                     
2408                     long screenId = item.screenId;                                                       
2409                     if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                
2410                             unusedScreens.contains(screenId)) {                                          
2411                         unusedScreens.remove(screenId);                                                  
2412                     }                                                                                    
2413                 }                                                                                        
2414                                                                                                          
2415                 // If there are any empty screens remove them, and update.                               
2416                 if (unusedScreens.size() != 0) {                                                         
2417                     sBgWorkspaceScreens.removeAll(unusedScreens);                                        
2418                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2419                 }                                                                                        
2420                                                                                                          
2421                 if (DEBUG_LOADERS) {                                                                     
2422                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2423                     Log.d(TAG, "workspace layout: ");                                                    
2424                     int nScreens = occupied.size();                                                      
2425                     for (int y = 0; y < countY; y++) {                                                   
2426                         String line = "";                                                                
2427                                                                                                          
2428                         for (int i = 0; i < nScreens; i++) {                                             
2429                             long screenId = occupied.keyAt(i);                                           
2430                             if (screenId > 0) {                                                          
2431                                 line += " | ";                                                           
2432                             }                                                                            
2433                             ItemInfo[][] screen = occupied.valueAt(i);                                   
2434                             for (int x = 0; x < countX; x++) {                                           
2435                                 if (x < screen.length && y < screen[x].length) {                         
2436                                     line += (screen[x][y] != null) ? "#" : ".";                          
2437                                 } else {                                                                 
2438                                     line += "!";                                                         
2439                                 }                                                                        
2440                             }                                                                            
2441                         }                                                                                
2442                         Log.d(TAG, "[ " + line + " ]");                                                  
2443                     }                                                                                    
2444                 }                                                                                        
2445             }                                                                                            
2446         }                                                                                                
2447                                                                                                          
2448         /**                                                                                              
2449          * Partially updates the item without any notification. Must be called on the worker thread.     
2450          */                                                                                              
2451         private void updateItem(long itemId, ContentValues update) {                                     
2452             mContext.getContentResolver().update(                                                        
2453                     LauncherSettings.Favorites.CONTENT_URI,                                              
2454                     update,                                                                              
2455                     BaseColumns._ID + "= ?",                                                             
2456                     new String[]{Long.toString(itemId)});                                                
2457         }                                                                                                
2458                                                                                                          
2459         /** Filters the set of items who are directly or indirectly (via another container) on the       
2460          * specified screen. */                                                                          
2461         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2462                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2463                 ArrayList<ItemInfo> currentScreenItems,                                                  
2464                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2465             // Purge any null ItemInfos                                                                  
2466             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2467             while (iter.hasNext()) {                                                                     
2468                 ItemInfo i = iter.next();                                                                
2469                 if (i == null) {                                                                         
2470                     iter.remove();                                                                       
2471                 }                                                                                        
2472             }                                                                                            
2473                                                                                                          
2474             // Order the set of items by their containers first, this allows use to walk through the     
2475             // list sequentially, build up a list of containers that are in the specified screen,        
2476             // as well as all items in those containers.                                                 
2477             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2478             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2479                 @Override                                                                                
2480                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2481                     return (int) (lhs.container - rhs.container);                                        
2482                 }                                                                                        
2483             });                                                                                          
2484             for (ItemInfo info : allWorkspaceItems) {                                                    
2485                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2486                     if (info.screenId == currentScreenId) {                                              
2487                         currentScreenItems.add(info);                                                    
2488                         itemsOnScreen.add(info.id);                                                      
2489                     } else {                                                                             
2490                         otherScreenItems.add(info);                                                      
2491                     }                                                                                    
2492                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2493                     currentScreenItems.add(info);                                                        
2494                     itemsOnScreen.add(info.id);                                                          
2495                 } else {                                                                                 
2496                     if (itemsOnScreen.contains(info.container)) {                                        
2497                         currentScreenItems.add(info);                                                    
2498                         itemsOnScreen.add(info.id);                                                      
2499                     } else {                                                                             
2500                         otherScreenItems.add(info);                                                      
2501                     }                                                                                    
2502                 }                                                                                        
2503             }                                                                                            
2504         }                                                                                                
2505                                                                                                          
2506         /** Filters the set of widgets which are on the specified screen. */                             
2507         private void filterCurrentAppWidgets(long currentScreenId,                                       
2508                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2509                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2510                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2511                                                                                                          
2512             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2513                 if (widget == null) continue;                                                            
2514                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2515                         widget.screenId == currentScreenId) {                                            
2516                     currentScreenWidgets.add(widget);                                                    
2517                 } else {                                                                                 
2518                     otherScreenWidgets.add(widget);                                                      
2519                 }                                                                                        
2520             }                                                                                            
2521         }                                                                                                
2522                                                                                                          
2523         /** Filters the set of folders which are on the specified screen. */                             
2524         private void filterCurrentFolders(long currentScreenId,                                          
2525                 LongArrayMap<ItemInfo> itemsIdMap,                                                       
2526                 LongArrayMap<FolderInfo> folders,                                                        
2527                 LongArrayMap<FolderInfo> currentScreenFolders,                                           
2528                 LongArrayMap<FolderInfo> otherScreenFolders) {                                           
2529                                                                                                          
2530             int total = folders.size();                                                                  
2531             for (int i = 0; i < total; i++) {                                                            
2532                 long id = folders.keyAt(i);                                                              
2533                 FolderInfo folder = folders.valueAt(i);                                                  
2534                                                                                                          
2535                 ItemInfo info = itemsIdMap.get(id);                                                      
2536                 if (info == null || folder == null) continue;                                            
2537                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2538                         info.screenId == currentScreenId) {                                              
2539                     currentScreenFolders.put(id, folder);                                                
2540                 } else {                                                                                 
2541                     otherScreenFolders.put(id, folder);                                                  
2542                 }                                                                                        
2543             }                                                                                            
2544         }                                                                                                
2545                                                                                                          
2546         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2547          * right) */                                                                                     
2548         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2549             final LauncherAppState app = LauncherAppState.getInstance();                                 
2550             final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                      
2551             // XXX: review this                                                                          
2552             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2553                 @Override                                                                                
2554                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2555                     int cellCountX = (int) profile.numColumns;                                           
2556                     int cellCountY = (int) profile.numRows;                                              
2557                     int screenOffset = cellCountX * cellCountY;                                          
2558                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2559                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2560                             lhs.cellY * cellCountX + lhs.cellX);                                         
2561                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2562                             rhs.cellY * cellCountX + rhs.cellX);                                         
2563                     return (int) (lr - rr);                                                              
2564                 }                                                                                        
2565             });                                                                                          
2566         }                                                                                                
2567                                                                                                          
2568         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2569                 final ArrayList<Long> orderedScreens) {                                                  
2570             final Runnable r = new Runnable() {                                                          
2571                 @Override                                                                                
2572                 public void run() {                                                                      
2573                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2574                     if (callbacks != null) {                                                             
2575                         callbacks.bindScreens(orderedScreens);                                           
2576                     }                                                                                    
2577                 }                                                                                        
2578             };                                                                                           
2579             runOnMainThread(r);                                                                          
2580         }                                                                                                
2581                                                                                                          
2582         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2583                 final ArrayList<ItemInfo> workspaceItems,                                                
2584                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2585                 final LongArrayMap<FolderInfo> folders,                                                  
2586                 ArrayList<Runnable> deferredBindRunnables) {                                             
2587                                                                                                          
2588             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2589                                                                                                          
2590             // Bind the workspace items                                                                  
2591             int N = workspaceItems.size();                                                               
2592             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2593                 final int start = i;                                                                     
2594                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2595                 final Runnable r = new Runnable() {                                                      
2596                     @Override                                                                            
2597                     public void run() {                                                                  
2598                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2599                         if (callbacks != null) {                                                         
2600                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2601                                     false);                                                              
2602                         }                                                                                
2603                     }                                                                                    
2604                 };                                                                                       
2605                 if (postOnMainThread) {                                                                  
2606                     synchronized (deferredBindRunnables) {                                               
2607                         deferredBindRunnables.add(r);                                                    
2608                     }                                                                                    
2609                 } else {                                                                                 
2610                     runOnMainThread(r);                                                                  
2611                 }                                                                                        
2612             }                                                                                            
2613                                                                                                          
2614             // Bind the folders                                                                          
2615             if (!folders.isEmpty()) {                                                                    
2616                 final Runnable r = new Runnable() {                                                      
2617                     public void run() {                                                                  
2618                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2619                         if (callbacks != null) {                                                         
2620                             callbacks.bindFolders(folders);                                              
2621                         }                                                                                
2622                     }                                                                                    
2623                 };                                                                                       
2624                 if (postOnMainThread) {                                                                  
2625                     synchronized (deferredBindRunnables) {                                               
2626                         deferredBindRunnables.add(r);                                                    
2627                     }                                                                                    
2628                 } else {                                                                                 
2629                     runOnMainThread(r);                                                                  
2630                 }                                                                                        
2631             }                                                                                            
2632                                                                                                          
2633             // Bind the widgets, one at a time                                                           
2634             N = appWidgets.size();                                                                       
2635             for (int i = 0; i < N; i++) {                                                                
2636                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2637                 final Runnable r = new Runnable() {                                                      
2638                     public void run() {                                                                  
2639                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2640                         if (callbacks != null) {                                                         
2641                             callbacks.bindAppWidget(widget);                                             
2642                         }                                                                                
2643                     }                                                                                    
2644                 };                                                                                       
2645                 if (postOnMainThread) {                                                                  
2646                     deferredBindRunnables.add(r);                                                        
2647                 } else {                                                                                 
2648                     runOnMainThread(r);                                                                  
2649                 }                                                                                        
2650             }                                                                                            
2651         }                                                                                                
2652                                                                                                          
2653         /**                                                                                              
2654          * Binds all loaded data to actual views on the main thread.                                     
2655          */                                                                                              
2656         private void bindWorkspace(int synchronizeBindPage) {                                            
2657             final long t = SystemClock.uptimeMillis();                                                   
2658             Runnable r;                                                                                  
2659                                                                                                          
2660             // Don't use these two variables in any of the callback runnables.                           
2661             // Otherwise we hold a reference to them.                                                    
2662             final Callbacks oldCallbacks = mCallbacks.get();                                             
2663             if (oldCallbacks == null) {                                                                  
2664                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2665                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2666                 return;                                                                                  
2667             }                                                                                            
2668                                                                                                          
2669             // Save a copy of all the bg-thread collections                                              
2670             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2671             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2672                     new ArrayList<LauncherAppWidgetInfo>();                                              
2673             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2674                                                                                                          
2675             final LongArrayMap<FolderInfo> folders;                                                      
2676             final LongArrayMap<ItemInfo> itemsIdMap;                                                     
2677                                                                                                          
2678             synchronized (sBgLock) {                                                                     
2679                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2680                 appWidgets.addAll(sBgAppWidgets);                                                        
2681                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2682                                                                                                          
2683                 folders = sBgFolders.clone();                                                            
2684                 itemsIdMap = sBgItemsIdMap.clone();                                                      
2685             }                                                                                            
2686                                                                                                          
2687             final boolean isLoadingSynchronously =                                                       
2688                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2689             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2690                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2691             if (currScreen >= orderedScreenIds.size()) {                                                 
2692                 // There may be no workspace screens (just hotseat items and an empty page).             
2693                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2694             }                                                                                            
2695             final int currentScreen = currScreen;                                                        
2696             final long currentScreenId = currentScreen < 0                                               
2697                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2698                                                                                                          
2699             // Load all the items that are on the current page first (and in the process, unbind         
2700             // all the existing workspace items before we call startBinding() below.                     
2701             unbindWorkspaceItemsOnMainThread();                                                          
2702                                                                                                          
2703             // Separate the items that are on the current screen, and all the other remaining items      
2704             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2705             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2706             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2707                     new ArrayList<LauncherAppWidgetInfo>();                                              
2708             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2709                     new ArrayList<LauncherAppWidgetInfo>();                                              
2710             LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();                              
2711             LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();                                
2712                                                                                                          
2713             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2714                     otherWorkspaceItems);                                                                
2715             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2716                     otherAppWidgets);                                                                    
2717             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2718                     otherFolders);                                                                       
2719             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2720             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2721                                                                                                          
2722             // Tell the workspace that we're about to start binding items                                
2723             r = new Runnable() {                                                                         
2724                 public void run() {                                                                      
2725                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2726                     if (callbacks != null) {                                                             
2727                         callbacks.startBinding();                                                        
2728                     }                                                                                    
2729                 }                                                                                        
2730             };                                                                                           
2731             runOnMainThread(r);                                                                          
2732                                                                                                          
2733             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2734                                                                                                          
2735             // Load items on the current page                                                            
2736             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2737                     currentFolders, null);                                                               
2738             if (isLoadingSynchronously) {                                                                
2739                 r = new Runnable() {                                                                     
2740                     public void run() {                                                                  
2741                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2742                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2743                             callbacks.onPageBoundSynchronously(currentScreen);                           
2744                         }                                                                                
2745                     }                                                                                    
2746                 };                                                                                       
2747                 runOnMainThread(r);                                                                      
2748             }                                                                                            
2749                                                                                                          
2750             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2751             // work until after the first render)                                                        
2752             synchronized (mDeferredBindRunnables) {                                                      
2753                 mDeferredBindRunnables.clear();                                                          
2754             }                                                                                            
2755             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2756                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2757                                                                                                          
2758             // Tell the workspace that we're done binding items                                          
2759             r = new Runnable() {                                                                         
2760                 public void run() {                                                                      
2761                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2762                     if (callbacks != null) {                                                             
2763                         callbacks.finishBindingItems();                                                  
2764                     }                                                                                    
2765                                                                                                          
2766                     // If we're profiling, ensure this is the last thing in the queue.                   
2767                     if (DEBUG_LOADERS) {                                                                 
2768                         Log.d(TAG, "bound workspace in "                                                 
2769                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2770                     }                                                                                    
2771                                                                                                          
2772                     mIsLoadingAndBindingWorkspace = false;                                               
2773                 }                                                                                        
2774             };                                                                                           
2775             if (isLoadingSynchronously) {                                                                
2776                 synchronized (mDeferredBindRunnables) {                                                  
2777                     mDeferredBindRunnables.add(r);                                                       
2778                 }                                                                                        
2779             } else {                                                                                     
2780                 runOnMainThread(r);                                                                      
2781             }                                                                                            
2782         }                                                                                                
2783                                                                                                          
2784         private void loadAndBindAllApps() {                                                              
2785             if (DEBUG_LOADERS) {                                                                         
2786                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2787             }                                                                                            
2788             if (!mAllAppsLoaded) {                                                                       
2789                 loadAllApps();                                                                           
2790                 synchronized (LoaderTask.this) {                                                         
2791                     if (mStopped) {                                                                      
2792                         return;                                                                          
2793                     }                                                                                    
2794                 }                                                                                        
2795                 updateIconCache();                                                                       
2796                 synchronized (LoaderTask.this) {                                                         
2797                     if (mStopped) {                                                                      
2798                         return;                                                                          
2799                     }                                                                                    
2800                     mAllAppsLoaded = true;                                                               
2801                 }                                                                                        
2802             } else {                                                                                     
2803                 onlyBindAllApps();                                                                       
2804             }                                                                                            
2805         }                                                                                                
2806                                                                                                          
2807         private void updateIconCache() {                                                                 
2808             // Ignore packages which have a promise icon.                                                
2809             HashSet<String> packagesToIgnore = new HashSet<>();                                          
2810             synchronized (sBgLock) {                                                                     
2811                 for (ItemInfo info : sBgItemsIdMap) {                                                    
2812                     if (info instanceof ShortcutInfo) {                                                  
2813                         ShortcutInfo si = (ShortcutInfo) info;                                           
2814                         if (si.isPromise() && si.getTargetComponent() != null) {                         
2815                             packagesToIgnore.add(si.getTargetComponent().getPackageName());              
2816                         }                                                                                
2817                     } else if (info instanceof LauncherAppWidgetInfo) {                                  
2818                         LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;                       
2819                         if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {        
2820                             packagesToIgnore.add(lawi.providerName.getPackageName());                    
2821                         }                                                                                
2822                     }                                                                                    
2823                 }                                                                                        
2824             }                                                                                            
2825             mIconCache.updateDbIcons(packagesToIgnore);                                                  
2826         }                                                                                                
2827                                                                                                          
2828         private void onlyBindAllApps() {                                                                 
2829             final Callbacks oldCallbacks = mCallbacks.get();                                             
2830             if (oldCallbacks == null) {                                                                  
2831                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2832                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2833                 return;                                                                                  
2834             }                                                                                            
2835                                                                                                          
2836             // shallow copy                                                                              
2837             @SuppressWarnings("unchecked")                                                               
2838             final ArrayList<AppInfo> list                                                                
2839                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2840             final WidgetsModel widgetList = mBgWidgetsModel.clone();                                     
2841             Runnable r = new Runnable() {                                                                
2842                 public void run() {                                                                      
2843                     final long t = SystemClock.uptimeMillis();                                           
2844                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2845                     if (callbacks != null) {                                                             
2846                         callbacks.bindAllApplications(list);                                             
2847                         callbacks.bindAllPackages(widgetList);                                           
2848                     }                                                                                    
2849                     if (DEBUG_LOADERS) {                                                                 
2850                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2851                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2852                     }                                                                                    
2853                 }                                                                                        
2854             };                                                                                           
2855             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2856             if (isRunningOnMainThread) {                                                                 
2857                 r.run();                                                                                 
2858             } else {                                                                                     
2859                 mHandler.post(r);                                                                        
2860             }                                                                                            
2861         }                                                                                                
2862                                                                                                          
2863         private void loadAllApps() {                                                                     
2864             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2865                                                                                                          
2866             final Callbacks oldCallbacks = mCallbacks.get();                                             
2867             if (oldCallbacks == null) {                                                                  
2868                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2869                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2870                 return;                                                                                  
2871             }                                                                                            
2872                                                                                                          
2873             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2874                                                                                                          
2875             // Clear the list of apps                                                                    
2876             mBgAllAppsList.clear();                                                                      
2877             for (UserHandleCompat user : profiles) {                                                     
2878                 // Query for the set of apps                                                             
2879                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                     
2880                 final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); 
2881                 if (DEBUG_LOADERS) {                                                                     
2882                     Log.d(TAG, "getActivityList took "                                                   
2883                             + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);             
2884                     Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);         
2885                 }                                                                                        
2886                 // Fail if we don't have any apps                                                        
2887                 // TODO: Fix this. Only fail for the current user.                                       
2888                 if (apps == null || apps.isEmpty()) {                                                    
2889                     return;                                                                              
2890                 }                                                                                        
2891                                                                                                          
2892                 // Create the ApplicationInfos                                                           
2893                 for (int i = 0; i < apps.size(); i++) {                                                  
2894                     LauncherActivityInfoCompat app = apps.get(i);                                        
2895                     // This builds the icon bitmaps.                                                     
2896                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2897                 }                                                                                        
2898                                                                                                          
2899                 final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);   
2900                 if (heuristic != null) {                                                                 
2901                     runAfterBindCompletes(new Runnable() {                                               
2902                                                                                                          
2903                         @Override                                                                        
2904                         public void run() {                                                              
2905                             heuristic.processUserApps(apps);                                             
2906                         }                                                                                
2907                     });                                                                                  
2908                 }                                                                                        
2909             }                                                                                            
2910             // Huh? Shouldn't this be inside the Runnable below?                                         
2911             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2912             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2913                                                                                                          
2914             // Post callback on main thread                                                              
2915             mHandler.post(new Runnable() {                                                               
2916                 public void run() {                                                                      
2917                                                                                                          
2918                     final long bindTime = SystemClock.uptimeMillis();                                    
2919                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2920                     if (callbacks != null) {                                                             
2921                         callbacks.bindAllApplications(added);                                            
2922                         if (DEBUG_LOADERS) {                                                             
2923                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2924                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2925                         }                                                                                
2926                     } else {                                                                             
2927                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2928                     }                                                                                    
2929                 }                                                                                        
2930             });                                                                                          
2931             // Cleanup any data stored for a deleted user.                                               
2932             ManagedProfileHeuristic.processAllUsers(profiles, mContext);                                 
2933                                                                                                          
2934             loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks),             
2935                     true /* refresh */);                                                                 
2936             if (DEBUG_LOADERS) {                                                                         
2937                 Log.d(TAG, "Icons processed in "                                                         
2938                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2939             }                                                                                            
2940         }                                                                                                
2941                                                                                                          
2942         public void dumpState() {                                                                        
2943             synchronized (sBgLock) {                                                                     
2944                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2945                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2946                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2947                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2948             }                                                                                            
2949         }                                                                                                
2950     }                                                                                                    
2951                                                                                                          
2952     /**                                                                                                  
2953      * Called when the icons for packages have been updated in the icon cache.                           
2954      */                                                                                                  
2955     public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {          
2956         final Callbacks callbacks = getCallback();                                                       
2957         final ArrayList<AppInfo> updatedApps = new ArrayList<>();                                        
2958         final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();                              
2959                                                                                                          
2960         // If any package icon has changed (app was updated while launcher was dead),                    
2961         // update the corresponding shortcuts.                                                           
2962         synchronized (sBgLock) {                                                                         
2963             for (ItemInfo info : sBgItemsIdMap) {                                                        
2964                 if (info instanceof ShortcutInfo && user.equals(info.user)                               
2965                         && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {          
2966                     ShortcutInfo si = (ShortcutInfo) info;                                               
2967                     ComponentName cn = si.getTargetComponent();                                          
2968                     if (cn != null && updatedPackages.contains(cn.getPackageName())) {                   
2969                         si.updateIcon(mIconCache);                                                       
2970                         updatedShortcuts.add(si);                                                        
2971                     }                                                                                    
2972                 }                                                                                        
2973             }                                                                                            
2974             mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);                     
2975         }                                                                                                
2976                                                                                                          
2977         if (!updatedShortcuts.isEmpty()) {                                                               
2978             final UserHandleCompat userFinal = user;                                                     
2979             mHandler.post(new Runnable() {                                                               
2980                                                                                                          
2981                 public void run() {                                                                      
2982                     Callbacks cb = getCallback();                                                        
2983                     if (cb != null && callbacks == cb) {                                                 
2984                         cb.bindShortcutsChanged(updatedShortcuts,                                        
2985                                 new ArrayList<ShortcutInfo>(), userFinal);                               
2986                     }                                                                                    
2987                 }                                                                                        
2988             });                                                                                          
2989         }                                                                                                
2990                                                                                                          
2991         if (!updatedApps.isEmpty()) {                                                                    
2992             mHandler.post(new Runnable() {                                                               
2993                                                                                                          
2994                 public void run() {                                                                      
2995                     Callbacks cb = getCallback();                                                        
2996                     if (cb != null && callbacks == cb) {                                                 
2997                         cb.bindAppsUpdated(updatedApps);                                                 
2998                     }                                                                                    
2999                 }                                                                                        
3000             });                                                                                          
3001         }                                                                                                
3002                                                                                                          
3003         // Reload widget list. No need to refresh, as we only want to update the icons and labels.       
3004         loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);                             
3005     }                                                                                                    
3006                                                                                                          
3007     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
3008         sWorker.post(task);                                                                              
3009     }                                                                                                    
3010                                                                                                          
3011     @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {                                       
3012                                                                                                          
3013         @Override                                                                                        
3014         public void onReceive(Context context, Intent intent) {                                          
3015             synchronized (sBgLock) {                                                                     
3016                 final LauncherAppsCompat launcherApps = LauncherAppsCompat                               
3017                         .getInstance(mApp.getContext());                                                 
3018                 final PackageManager manager = context.getPackageManager();                              
3019                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
3020                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
3021                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
3022                     UserHandleCompat user = entry.getKey();                                              
3023                     packagesRemoved.clear();                                                             
3024                     packagesUnavailable.clear();                                                         
3025                     for (String pkg : entry.getValue()) {                                                
3026                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
3027                             boolean packageOnSdcard = launcherApps.isAppEnabled(                         
3028                                     manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);              
3029                             if (packageOnSdcard) {                                                       
3030                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
3031                                 packagesUnavailable.add(pkg);                                            
3032                             } else {                                                                     
3033                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
3034                                 packagesRemoved.add(pkg);                                                
3035                             }                                                                            
3036                         }                                                                                
3037                     }                                                                                    
3038                     if (!packagesRemoved.isEmpty()) {                                                    
3039                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,       
3040                                 packagesRemoved.toArray(new String[packagesRemoved.size()]), user));     
3041                     }                                                                                    
3042                     if (!packagesUnavailable.isEmpty()) {                                                
3043                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,  
3044                                 packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user🔵
3045                     }                                                                                    
3046                 }                                                                                        
3047                 sPendingPackages.clear();                                                                
3048             }                                                                                            
3049         }                                                                                                
3050     }                                                                                                    
3051                                                                                                          
3052     private class PackageUpdatedTask implements Runnable {                                               
3053         int mOp;                                                                                         
3054         String[] mPackages;                                                                              
3055         UserHandleCompat mUser;                                                                          
3056                                                                                                          
3057         public static final int OP_NONE = 0;                                                             
3058         public static final int OP_ADD = 1;                                                              
3059         public static final int OP_UPDATE = 2;                                                           
3060         public static final int OP_REMOVE = 3; // uninstlled                                             
3061         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
3062                                                                                                          
3063                                                                                                          
3064         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
3065             mOp = op;                                                                                    
3066             mPackages = packages;                                                                        
3067             mUser = user;                                                                                
3068         }                                                                                                
3069                                                                                                          
3070         public void run() {                                                                              
3071             if (!mHasLoaderCompletedOnce) {                                                              
3072                 // Loader has not yet run.                                                               
3073                 return;                                                                                  
3074             }                                                                                            
3075             final Context context = mApp.getContext();                                                   
3076                                                                                                          
3077             final String[] packages = mPackages;                                                         
3078             final int N = packages.length;                                                               
3079             switch (mOp) {                                                                               
3080                 case OP_ADD: {                                                                           
3081                     for (int i=0; i<N; i++) {                                                            
3082                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
3083                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
3084                         mBgAllAppsList.addPackage(context, packages[i], mUser);                          
3085                     }                                                                                    
3086                                                                                                          
3087                     ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);     
3088                     if (heuristic != null) {                                                             
3089                         heuristic.processPackageAdd(mPackages);                                          
3090                     }                                                                                    
3091                     break;                                                                               
3092                 }                                                                                        
3093                 case OP_UPDATE:                                                                          
3094                     for (int i=0; i<N; i++) {                                                            
3095                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
3096                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
3097                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
3098                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
3099                     }                                                                                    
3100                     break;                                                                               
3101                 case OP_REMOVE: {                                                                        
3102                     ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);     
3103                     if (heuristic != null) {                                                             
3104                         heuristic.processPackageRemoved(mPackages);                                      
3105                     }                                                                                    
3106                     for (int i=0; i<N; i++) {                                                            
3107                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3108                         mIconCache.removeIconsForPkg(packages[i], mUser);                                
3109                     }                                                                                    
3110                     // Fall through                                                                      
3111                 }                                                                                        
3112                 case OP_UNAVAILABLE:                                                                     
3113                     for (int i=0; i<N; i++) {                                                            
3114                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3115                         mBgAllAppsList.removePackage(packages[i], mUser);                                
3116                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
3117                     }                                                                                    
3118                     break;                                                                               
3119             }                                                                                            
3120                                                                                                          
3121             ArrayList<AppInfo> added = null;                                                             
3122             ArrayList<AppInfo> modified = null;                                                          
3123             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
3124                                                                                                          
3125             if (mBgAllAppsList.added.size() > 0) {                                                       
3126                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
3127                 mBgAllAppsList.added.clear();                                                            
3128             }                                                                                            
3129             if (mBgAllAppsList.modified.size() > 0) {                                                    
3130                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
3131                 mBgAllAppsList.modified.clear();                                                         
3132             }                                                                                            
3133             if (mBgAllAppsList.removed.size() > 0) {                                                     
3134                 removedApps.addAll(mBgAllAppsList.removed);                                              
3135                 mBgAllAppsList.removed.clear();                                                          
3136             }                                                                                            
3137                                                                                                          
3138             final Callbacks callbacks = getCallback();                                                   
3139             if (callbacks == null) {                                                                     
3140                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
3141                 return;                                                                                  
3142             }                                                                                            
3143                                                                                                          
3144             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                   
3145                     new HashMap<ComponentName, AppInfo>();                                               
3146                                                                                                          
3147             if (added != null) {                                                                         
3148                 addAppsToAllApps(context, added);                                                        
3149                 for (AppInfo ai : added) {                                                               
3150                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3151                 }                                                                                        
3152             }                                                                                            
3153                                                                                                          
3154             if (modified != null) {                                                                      
3155                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
3156                 for (AppInfo ai : modified) {                                                            
3157                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3158                 }                                                                                        
3159                                                                                                          
3160                 mHandler.post(new Runnable() {                                                           
3161                     public void run() {                                                                  
3162                         Callbacks cb = getCallback();                                                    
3163                         if (callbacks == cb && cb != null) {                                             
3164                             callbacks.bindAppsUpdated(modifiedFinal);                                    
3165                         }                                                                                
3166                     }                                                                                    
3167                 });                                                                                      
3168             }                                                                                            
3169                                                                                                          
3170             // Update shortcut infos                                                                     
3171             if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                     
3172                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
3173                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
3174                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
3175                                                                                                          
3176                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
3177                 synchronized (sBgLock) {                                                                 
3178                     for (ItemInfo info : sBgItemsIdMap) {                                                
3179                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                   
3180                             ShortcutInfo si = (ShortcutInfo) info;                                       
3181                             boolean infoUpdated = false;                                                 
3182                             boolean shortcutUpdated = false;                                             
3183                                                                                                          
3184                             // Update shortcuts which use iconResource.                                  
3185                             if ((si.iconResource != null)                                                
3186                                     && packageSet.contains(si.iconResource.packageName)) {               
3187                                 Bitmap icon = Utilities.createIconBitmap(                                
3188                                         si.iconResource.packageName,                                     
3189                                         si.iconResource.resourceName, context);                          
3190                                 if (icon != null) {                                                      
3191                                     si.setIcon(icon);                                                    
3192                                     si.usingFallbackIcon = false;                                        
3193                                     infoUpdated = true;                                                  
3194                                 }                                                                        
3195                             }                                                                            
3196                                                                                                          
3197                             ComponentName cn = si.getTargetComponent();                                  
3198                             if (cn != null && packageSet.contains(cn.getPackageName())) {                
3199                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
3200                                                                                                          
3201                                 if (si.isPromise()) {                                                    
3202                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
3203                                         // Auto install icon                                             
3204                                         PackageManager pm = context.getPackageManager();                 
3205                                         ResolveInfo matched = pm.resolveActivity(                        
3206                                                 new Intent(Intent.ACTION_MAIN)                           
3207                                                 .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), 
3208                                                 PackageManager.MATCH_DEFAULT_ONLY);                      
3209                                         if (matched == null) {                                           
3210                                             // Try to find the best match activity.                      
3211                                             Intent intent = pm.getLaunchIntentForPackage(                
3212                                                     cn.getPackageName());                                
3213                                             if (intent != null) {                                        
3214                                                 cn = intent.getComponent();                              
3215                                                 appInfo = addedOrUpdatedApps.get(cn);                    
3216                                             }                                                            
3217                                                                                                          
3218                                             if ((intent == null) || (appInfo == null)) {                 
3219                                                 removedShortcuts.add(si);                                
3220                                                 continue;                                                
3221                                             }                                                            
3222                                             si.promisedIntent = intent;                                  
3223                                         }                                                                
3224                                     }                                                                    
3225                                                                                                          
3226                                     // Restore the shortcut.                                             
3227                                     if (appInfo != null) {                                               
3228                                         si.flags = appInfo.flags;                                        
3229                                     }                                                                    
3230                                                                                                          
3231                                     si.intent = si.promisedIntent;                                       
3232                                     si.promisedIntent = null;                                            
3233                                     si.status = ShortcutInfo.DEFAULT;                                    
3234                                     infoUpdated = true;                                                  
3235                                     si.updateIcon(mIconCache);                                           
3236                                 }                                                                        
3237                                                                                                          
3238                                 if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())  
3239                                         && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATIO🔵
3240                                     si.updateIcon(mIconCache);                                           
3241                                     si.title = Utilities.trim(appInfo.title);                            
3242                                     si.contentDescription = appInfo.contentDescription;                  
3243                                     infoUpdated = true;                                                  
3244                                 }                                                                        
3245                                                                                                          
3246                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
3247                                     // Since package was just updated, the target must be available now. 
3248                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
3249                                     shortcutUpdated = true;                                              
3250                                 }                                                                        
3251                             }                                                                            
3252                                                                                                          
3253                             if (infoUpdated || shortcutUpdated) {                                        
3254                                 updatedShortcuts.add(si);                                                
3255                             }                                                                            
3256                             if (infoUpdated) {                                                           
3257                                 updateItemInDatabase(context, si);                                       
3258                             }                                                                            
3259                         } else if (info instanceof LauncherAppWidgetInfo) {                              
3260                             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;             
3261                             if (mUser.equals(widgetInfo.user)                                            
3262                                     && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_🔵
3263                                     && packageSet.contains(widgetInfo.providerName.getPackageName())) {  
3264                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
3265                                 widgets.add(widgetInfo);                                                 
3266                                 updateItemInDatabase(context, widgetInfo);                               
3267                             }                                                                            
3268                         }                                                                                
3269                     }                                                                                    
3270                 }                                                                                        
3271                                                                                                          
3272                 if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                        
3273                     mHandler.post(new Runnable() {                                                       
3274                                                                                                          
3275                         public void run() {                                                              
3276                             Callbacks cb = getCallback();                                                
3277                             if (callbacks == cb && cb != null) {                                         
3278                                 callbacks.bindShortcutsChanged(                                          
3279                                         updatedShortcuts, removedShortcuts, mUser);                      
3280                             }                                                                            
3281                         }                                                                                
3282                     });                                                                                  
3283                     if (!removedShortcuts.isEmpty()) {                                                   
3284                         deleteItemsFromDatabase(context, removedShortcuts);                              
3285                     }                                                                                    
3286                 }                                                                                        
3287                 if (!widgets.isEmpty()) {                                                                
3288                     mHandler.post(new Runnable() {                                                       
3289                         public void run() {                                                              
3290                             Callbacks cb = getCallback();                                                
3291                             if (callbacks == cb && cb != null) {                                         
3292                                 callbacks.bindWidgetsRestored(widgets);                                  
3293                             }                                                                            
3294                         }                                                                                
3295                     });                                                                                  
3296                 }                                                                                        
3297             }                                                                                            
3298                                                                                                          
3299             final ArrayList<String> removedPackageNames =                                                
3300                     new ArrayList<String>();                                                             
3301             if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                             
3302                 // Mark all packages in the broadcast to be removed                                      
3303                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3304             } else if (mOp == OP_UPDATE) {                                                               
3305                 // Mark disabled packages in the broadcast to be removed                                 
3306                 for (int i=0; i<N; i++) {                                                                
3307                     if (isPackageDisabled(context, packages[i], mUser)) {                                
3308                         removedPackageNames.add(packages[i]);                                            
3309                     }                                                                                    
3310                 }                                                                                        
3311             }                                                                                            
3312                                                                                                          
3313             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
3314                 final int removeReason;                                                                  
3315                 if (mOp == OP_UNAVAILABLE) {                                                             
3316                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
3317                 } else {                                                                                 
3318                     // Remove all the components associated with this package                            
3319                     for (String pn : removedPackageNames) {                                              
3320                         deletePackageFromDatabase(context, pn, mUser);                                   
3321                     }                                                                                    
3322                     // Remove all the specific components                                                
3323                     for (AppInfo a : removedApps) {                                                      
3324                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
3325                         deleteItemsFromDatabase(context, infos);                                         
3326                     }                                                                                    
3327                     removeReason = 0;                                                                    
3328                 }                                                                                        
3329                                                                                                          
3330                 // Remove any queued items from the install queue                                        
3331                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
3332                 // Call the components-removed callback                                                  
3333                 mHandler.post(new Runnable() {                                                           
3334                     public void run() {                                                                  
3335                         Callbacks cb = getCallback();                                                    
3336                         if (callbacks == cb && cb != null) {                                             
3337                             callbacks.bindComponentsRemoved(                                             
3338                                     removedPackageNames, removedApps, mUser, removeReason);              
3339                         }                                                                                
3340                     }                                                                                    
3341                 });                                                                                      
3342             }                                                                                            
3343                                                                                                          
3344             // onProvidersChanged method (API >= 17) already refreshed the widget list                   
3345             loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17);              
3346                                                                                                          
3347             // Write all the logs to disk                                                                
3348             mHandler.post(new Runnable() {                                                               
3349                 public void run() {                                                                      
3350                     Callbacks cb = getCallback();                                                        
3351                     if (callbacks == cb && cb != null) {                                                 
3352                         callbacks.dumpLogsToLocalData();                                                 
3353                     }                                                                                    
3354                 }                                                                                        
3355             });                                                                                          
3356         }                                                                                                
3357     }                                                                                                    
3358                                                                                                          
3359     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,                
3360             boolean refresh) {                                                                           
3361         ArrayList<LauncherAppWidgetProviderInfo> results =                                               
3362                 new ArrayList<LauncherAppWidgetProviderInfo>();                                          
3363         try {                                                                                            
3364             synchronized (sBgLock) {                                                                     
3365                 if (sBgWidgetProviders == null || refresh) {                                             
3366                     HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders              
3367                             = new HashMap<>();                                                           
3368                     AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);             
3369                     LauncherAppWidgetProviderInfo info;                                                  
3370                                                                                                          
3371                     List<AppWidgetProviderInfo> widgets = wm.getAllProviders();                          
3372                     for (AppWidgetProviderInfo pInfo : widgets) {                                        
3373                         info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);           
3374                         UserHandleCompat user = wm.getUser(info);                                        
3375                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
3376                     }                                                                                    
3377                                                                                                          
3378                     Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values(); 
3379                     for (CustomAppWidget widget : customWidgets) {                                       
3380                         info = new LauncherAppWidgetProviderInfo(context, widget);                       
3381                         UserHandleCompat user = wm.getUser(info);                                        
3382                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
3383                     }                                                                                    
3384                     // Replace the global list at the very end, so that if there is an exception,        
3385                     // previously loaded provider list is used.                                          
3386                     sBgWidgetProviders = tmpWidgetProviders;                                             
3387                 }                                                                                        
3388                 results.addAll(sBgWidgetProviders.values());                                             
3389                 return results;                                                                          
3390             }                                                                                            
3391         } catch (Exception e) {                                                                          
3392             if (e.getCause() instanceof TransactionTooLargeException) {                                  
3393                 // the returned value may be incomplete and will not be refreshed until the next         
3394                 // time Launcher starts.                                                                 
3395                 // TODO: after figuring out a repro step, introduce a dirty bit to check when            
3396                 // onResume is called to refresh the widget provider list.                               
3397                 synchronized (sBgLock) {                                                                 
3398                     if (sBgWidgetProviders != null) {                                                    
3399                         results.addAll(sBgWidgetProviders.values());                                     
3400                     }                                                                                    
3401                     return results;                                                                      
3402                 }                                                                                        
3403             } else {                                                                                     
3404                 throw e;                                                                                 
3405             }                                                                                            
3406         }                                                                                                
3407     }                                                                                                    
3408                                                                                                          
3409     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,         
3410             UserHandleCompat user) {                                                                     
3411         synchronized (sBgLock) {                                                                         
3412             if (sBgWidgetProviders == null) {                                                            
3413                 getWidgetProviders(ctx, false /* refresh */);                                            
3414             }                                                                                            
3415             return sBgWidgetProviders.get(new ComponentKey(name, user));                                 
3416         }                                                                                                
3417     }                                                                                                    
3418                                                                                                          
3419     public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks,         
3420             final boolean refresh) {                                                                     
3421                                                                                                          
3422         runOnWorkerThread(new Runnable() {                                                               
3423             @Override                                                                                    
3424             public void run() {                                                                          
3425                 updateWidgetsModel(context, refresh);                                                    
3426                 final WidgetsModel model = mBgWidgetsModel.clone();                                      
3427                                                                                                          
3428                 mHandler.post(new Runnable() {                                                           
3429                     @Override                                                                            
3430                     public void run() {                                                                  
3431                         Callbacks cb = getCallback();                                                    
3432                         if (callbacks == cb && cb != null) {                                             
3433                             callbacks.bindAllPackages(model);                                            
3434                         }                                                                                
3435                     }                                                                                    
3436                 });                                                                                      
3437                 // update the Widget entries inside DB on the worker thread.                             
3438                 LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(                  
3439                         model.getRawList());                                                             
3440             }                                                                                            
3441         });                                                                                              
3442     }                                                                                                    
3443                                                                                                          
3444     /**                                                                                                  
3445      * Returns a list of ResolveInfos/AppWidgetInfos.                                                    
3446      *                                                                                                   
3447      * @see #loadAndBindWidgetsAndShortcuts                                                              
3448      */                                                                                                  
3449     @Thunk void updateWidgetsModel(Context context, boolean refresh) {                                   
3450         PackageManager packageManager = context.getPackageManager();                                     
3451         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3452         widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));                                
3453         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3454         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3455         mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);                                     
3456     }                                                                                                    
3457                                                                                                          
3458     @Thunk static boolean isPackageDisabled(Context context, String packageName,                         
3459             UserHandleCompat user) {                                                                     
3460         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3461         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3462     }                                                                                                    
3463                                                                                                          
3464     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3465             UserHandleCompat user) {                                                                     
3466         if (cn == null) {                                                                                
3467             return false;                                                                                
3468         }                                                                                                
3469         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3470         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3471             return false;                                                                                
3472         }                                                                                                
3473         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3474     }                                                                                                    
3475                                                                                                          
3476     public static boolean isValidPackage(Context context, String packageName,                            
3477             UserHandleCompat user) {                                                                     
3478         if (packageName == null) {                                                                       
3479             return false;                                                                                
3480         }                                                                                                
3481         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3482         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3483     }                                                                                                    
3484                                                                                                          
3485     /**                                                                                                  
3486      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3487      * to a package that is not yet installed on the system.                                             
3488      */                                                                                                  
3489     public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent,                     
3490             int promiseType, int itemType, CursorIconInfo iconInfo, Context context) {                   
3491         final ShortcutInfo info = new ShortcutInfo();                                                    
3492         info.user = UserHandleCompat.myUserHandle();                                                     
3493                                                                                                          
3494         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3495         // the fallback icon                                                                             
3496         if (icon == null) {                                                                              
3497             mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);              
3498         } else {                                                                                         
3499             info.setIcon(icon);                                                                          
3500         }                                                                                                
3501                                                                                                          
3502         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3503             String title = (c != null) ? c.getString(titleIndex) : null;                                 
3504             if (!TextUtils.isEmpty(title)) {                                                             
3505                 info.title = Utilities.trim(title);                                                      
3506             }                                                                                            
3507         } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                            
3508             if (TextUtils.isEmpty(info.title)) {                                                         
3509                 info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";                 
3510             }                                                                                            
3511         } else {                                                                                         
3512             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3513         }                                                                                                
3514                                                                                                          
3515         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3516         info.itemType = itemType;                                                                        
3517         info.promisedIntent = intent;                                                                    
3518         info.status = promiseType;                                                                       
3519         return info;                                                                                     
3520     }                                                                                                    
3521                                                                                                          
3522     /**                                                                                                  
3523      * Make an Intent object for a restored application or shortcut item that points                     
3524      * to the market page for the item.                                                                  
3525      */                                                                                                  
3526     @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                      
3527         ComponentName componentName = intent.getComponent();                                             
3528         return getMarketIntent(componentName.getPackageName());                                          
3529     }                                                                                                    
3530                                                                                                          
3531     static Intent getMarketIntent(String packageName) {                                                  
3532         return new Intent(Intent.ACTION_VIEW)                                                            
3533             .setData(new Uri.Builder()                                                                   
3534                 .scheme("market")                                                                        
3535                 .authority("details")                                                                    
3536                 .appendQueryParameter("id", packageName)                                                 
3537                 .build());                                                                               
3538     }                                                                                                    
3539                                                                                                          
3540     /**                                                                                                  
3541      * Make an ShortcutInfo object for a shortcut that is an application.                                
3542      *                                                                                                   
3543      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3544      */                                                                                                  
3545     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                        
3546             UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,             
3547             boolean allowMissingTarget, boolean useLowResIcon) {                                         
3548         if (user == null) {                                                                              
3549             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3550             return null;                                                                                 
3551         }                                                                                                
3552                                                                                                          
3553         ComponentName componentName = intent.getComponent();                                             
3554         if (componentName == null) {                                                                     
3555             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3556             return null;                                                                                 
3557         }                                                                                                
3558                                                                                                          
3559         Intent newIntent = new Intent(intent.getAction(), null);                                         
3560         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3561         newIntent.setComponent(componentName);                                                           
3562         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3563         if ((lai == null) && !allowMissingTarget) {                                                      
3564             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3565             return null;                                                                                 
3566         }                                                                                                
3567                                                                                                          
3568         final ShortcutInfo info = new ShortcutInfo();                                                    
3569         mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);                
3570         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                     
3571             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3572             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3573         }                                                                                                
3574                                                                                                          
3575         // from the db                                                                                   
3576         if (TextUtils.isEmpty(info.title) && c != null) {                                                
3577             info.title =  Utilities.trim(c.getString(titleIndex));                                       
3578         }                                                                                                
3579                                                                                                          
3580         // fall back to the class name of the activity                                                   
3581         if (info.title == null) {                                                                        
3582             info.title = componentName.getClassName();                                                   
3583         }                                                                                                
3584                                                                                                          
3585         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3586         info.user = user;                                                                                
3587         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3588         if (lai != null) {                                                                               
3589             info.flags = AppInfo.initFlags(lai);                                                         
3590         }                                                                                                
3591         return info;                                                                                     
3592     }                                                                                                    
3593                                                                                                          
3594     static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,                                 
3595             ItemInfoFilter f) {                                                                          
3596         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3597         for (ItemInfo i : infos) {                                                                       
3598             if (i instanceof ShortcutInfo) {                                                             
3599                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3600                 ComponentName cn = info.getTargetComponent();                                            
3601                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3602                     filtered.add(info);                                                                  
3603                 }                                                                                        
3604             } else if (i instanceof FolderInfo) {                                                        
3605                 FolderInfo info = (FolderInfo) i;                                                        
3606                 for (ShortcutInfo s : info.contents) {                                                   
3607                     ComponentName cn = s.getTargetComponent();                                           
3608                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3609                         filtered.add(s);                                                                 
3610                     }                                                                                    
3611                 }                                                                                        
3612             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3613                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3614                 ComponentName cn = info.providerName;                                                    
3615                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3616                     filtered.add(info);                                                                  
3617                 }                                                                                        
3618             }                                                                                            
3619         }                                                                                                
3620         return new ArrayList<ItemInfo>(filtered);                                                        
3621     }                                                                                                    
3622                                                                                                          
3623     @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                    
3624             final UserHandleCompat user) {                                                               
3625         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3626             @Override                                                                                    
3627             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3628                 if (info.user == null) {                                                                 
3629                     return cn.equals(cname);                                                             
3630                 } else {                                                                                 
3631                     return cn.equals(cname) && info.user.equals(user);                                   
3632                 }                                                                                        
3633             }                                                                                            
3634         };                                                                                               
3635         return filterItemInfos(sBgItemsIdMap, filter);                                                   
3636     }                                                                                                    
3637                                                                                                          
3638     /**                                                                                                  
3639      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3640      */                                                                                                  
3641     @Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,                                       
3642             int titleIndex, CursorIconInfo iconInfo) {                                                   
3643         final ShortcutInfo info = new ShortcutInfo();                                                    
3644         // Non-app shortcuts are only supported for current user.                                        
3645         info.user = UserHandleCompat.myUserHandle();                                                     
3646         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3647                                                                                                          
3648         // TODO: If there's an explicit component and we can't install that, delete it.                  
3649                                                                                                          
3650         info.title = Utilities.trim(c.getString(titleIndex));                                            
3651                                                                                                          
3652         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3653         // the fallback icon                                                                             
3654         if (icon == null) {                                                                              
3655             icon = mIconCache.getDefaultIcon(info.user);                                                 
3656             info.usingFallbackIcon = true;                                                               
3657         }                                                                                                
3658         info.setIcon(icon);                                                                              
3659         return info;                                                                                     
3660     }                                                                                                    
3661                                                                                                          
3662     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3663         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3664         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3665         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3666                                                                                                          
3667         if (intent == null) {                                                                            
3668             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3669             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3670             return null;                                                                                 
3671         }                                                                                                
3672                                                                                                          
3673         Bitmap icon = null;                                                                              
3674         boolean customIcon = false;                                                                      
3675         ShortcutIconResource iconResource = null;                                                        
3676                                                                                                          
3677         if (bitmap instanceof Bitmap) {                                                                  
3678             icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                 
3679             customIcon = true;                                                                           
3680         } else {                                                                                         
3681             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3682             if (extra instanceof ShortcutIconResource) {                                                 
3683                 iconResource = (ShortcutIconResource) extra;                                             
3684                 icon = Utilities.createIconBitmap(iconResource.packageName,                              
3685                         iconResource.resourceName, context);                                             
3686             }                                                                                            
3687         }                                                                                                
3688                                                                                                          
3689         final ShortcutInfo info = new ShortcutInfo();                                                    
3690                                                                                                          
3691         // Only support intents for current user for now. Intents sent from other                        
3692         // users wouldn't get here without intent forwarding anyway.                                     
3693         info.user = UserHandleCompat.myUserHandle();                                                     
3694         if (icon == null) {                                                                              
3695             icon = mIconCache.getDefaultIcon(info.user);                                                 
3696             info.usingFallbackIcon = true;                                                               
3697         }                                                                                                
3698         info.setIcon(icon);                                                                              
3699                                                                                                          
3700         info.title = Utilities.trim(name);                                                               
3701         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3702         info.intent = intent;                                                                            
3703         info.customIcon = customIcon;                                                                    
3704         info.iconResource = iconResource;                                                                
3705                                                                                                          
3706         return info;                                                                                     
3707     }                                                                                                    
3708                                                                                                          
3709     /**                                                                                                  
3710      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3711      * or make a new one.                                                                                
3712      */                                                                                                  
3713     @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {               
3714         // See if a placeholder was created for us already                                               
3715         FolderInfo folderInfo = folders.get(id);                                                         
3716         if (folderInfo == null) {                                                                        
3717             // No placeholder -- create a new instance                                                   
3718             folderInfo = new FolderInfo();                                                               
3719             folders.put(id, folderInfo);                                                                 
3720         }                                                                                                
3721         return folderInfo;                                                                               
3722     }                                                                                                    
3723                                                                                                          
3724                                                                                                          
3725     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3726         return (provider != null) && (provider.provider != null)                                         
3727                 && (provider.provider.getPackageName() != null);                                         
3728     }                                                                                                    
3729                                                                                                          
3730     public void dumpState() {                                                                            
3731         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3732         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3733         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3734         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3735         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3736         if (mLoaderTask != null) {                                                                       
3737             mLoaderTask.dumpState();                                                                     
3738         } else {                                                                                         
3739             Log.d(TAG, "mLoaderTask=null");                                                              
3740         }                                                                                                
3741     }                                                                                                    
3742                                                                                                          
3743     public Callbacks getCallback() {                                                                     
3744         return mCallbacks != null ? mCallbacks.get() : null;                                             
3745     }                                                                                                    
3746                                                                                                          
3747     /**                                                                                                  
3748      * @return {@link FolderInfo} if its already loaded.                                                 
3749      */                                                                                                  
3750     public FolderInfo findFolderById(Long folderId) {                                                    
3751         synchronized (sBgLock) {                                                                         
3752             return sBgFolders.get(folderId);                                                             
3753         }                                                                                                
3754     }                                                                                                    
3755                                                                                                          
3756     /**                                                                                                  
3757      * @return the looper for the worker thread which can be used to start background tasks.             
3758      */                                                                                                  
3759     public static Looper getWorkerLooper() {                                                             
3760         return sWorkerThread.getLooper();                                                                
3761     }                                                                                                    
3762 }                                                                                                        
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetProviderInfo;                                                          
  21 import android.content.BroadcastReceiver;                                                                
  22 import android.content.ComponentName;                                                                    
  23 import android.content.ContentProviderOperation;                                                         
  24 import android.content.ContentResolver;                                                                  
  25 import android.content.ContentValues;                                                                    
  26 import android.content.Context;                                                                          
  27 import android.content.Intent;                                                                           
  28 import android.content.Intent.ShortcutIconResource;                                                      
  29 import android.content.IntentFilter;                                                                     
  30 import android.content.pm.PackageManager;                                                                
  31 import android.content.pm.ProviderInfo;                                                                  
  32 import android.content.pm.ResolveInfo;                                                                   
  33 import android.database.Cursor;                                                                          
  34 import android.graphics.Bitmap;                                                                          
  35 import android.net.Uri;                                                                                  
  36 import android.os.Build;                                                                                 
  37 import android.os.Environment;                                                                           
  38 import android.os.Handler;                                                                               
  39 import android.os.HandlerThread;                                                                         
  40 import android.os.Looper;                                                                                
  41 import android.os.Parcelable;                                                                            
  42 import android.os.Process;                                                                               
  43 import android.os.SystemClock;                                                                           
  44 import android.os.TransactionTooLargeException;                                                          
  45 import android.provider.BaseColumns;                                                                     
  46 import android.text.TextUtils;                                                                           
  47 import android.util.Log;                                                                                 
  48 import android.util.LongSparseArray;                                                                     
  49 import android.util.Pair;                                                                                
  50                                                                                                          
  51 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  52 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  53 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  54 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  55 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  56 import com.android.launcher3.compat.UserHandleCompat;                                                    
  57 import com.android.launcher3.compat.UserManagerCompat;                                                   
  58 import com.android.launcher3.model.WidgetsModel;                                                         
  59 import com.android.launcher3.util.ComponentKey;                                                          
  60 import com.android.launcher3.util.CursorIconInfo;                                                        
  61 import com.android.launcher3.util.LongArrayMap;                                                          
  62 import com.android.launcher3.util.ManagedProfileHeuristic;                                               
  63 import com.android.launcher3.util.Thunk;                                                                 
  64                                                                                                          
  65 import java.lang.ref.WeakReference;                                                                      
  66 import java.net.URISyntaxException;                                                                      
  67 import java.security.InvalidParameterException;                                                          
  68 import java.util.ArrayList;                                                                              
  69 import java.util.Arrays;                                                                                 
  70 import java.util.Collection;                                                                             
  71 import java.util.Collections;                                                                            
  72 import java.util.Comparator;                                                                             
  73 import java.util.HashMap;                                                                                
  74 import java.util.HashSet;                                                                                
  75 import java.util.Iterator;                                                                               
  76 import java.util.List;                                                                                   
  77 import java.util.Map.Entry;                                                                              
  78 import java.util.Set;                                                                                    
  79                                                                                                          
  80 /**                                                                                                      
  81  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  82  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  83  * for the Launcher.                                                                                     
  84  */                                                                                                      
  85 public class LauncherModel extends BroadcastReceiver                                                     
  86         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                      
  87     static final boolean DEBUG_LOADERS = false;                                                          
  88     private static final boolean DEBUG_RECEIVER = false;                                                 
  89     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  90                                                                                                          
  91     static final String TAG = "Launcher.Model";                                                          
  92                                                                                                          
  93     public static final int LOADER_FLAG_NONE = 0;                                                        
  94     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  95     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  96                                                                                                          
  97     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  98     private static final long INVALID_SCREEN_ID = -1L;                                                   
  99                                                                                                          
 100     @Thunk final boolean mAppsCanBeOnRemoveableStorage;                                                  
 101     private final boolean mOldContentProviderExists;                                                     
 102                                                                                                          
 103     @Thunk final LauncherAppState mApp;                                                                  
 104     @Thunk final Object mLock = new Object();                                                            
 105     @Thunk DeferredHandler mHandler = new DeferredHandler();                                             
 106     @Thunk LoaderTask mLoaderTask;                                                                       
 107     @Thunk boolean mIsLoaderTaskRunning;                                                                 
 108     @Thunk boolean mHasLoaderCompletedOnce;                                                              
 109                                                                                                          
 110     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 111                                                                                                          
 112     @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");              
 113     static {                                                                                             
 114         sWorkerThread.start();                                                                           
 115     }                                                                                                    
 116     @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());                        
 117                                                                                                          
 118     // We start off with everything not loaded.  After that, we assume that                              
 119     // our monitoring of the package manager provides all updates and we never                           
 120     // need to do a requery.  These are only ever touched from the loader thread.                        
 121     @Thunk boolean mWorkspaceLoaded;                                                                     
 122     @Thunk boolean mAllAppsLoaded;                                                                       
 123                                                                                                          
 124     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 125     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 126     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 127     // a normal load, we also clear this set of Runnables.                                               
 128     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 129                                                                                                          
 130     /**                                                                                                  
 131      * Set of runnables to be called on the background thread after the workspace binding                
 132      * is complete.                                                                                      
 133      */                                                                                                  
 134     static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();                 
 135                                                                                                          
 136     @Thunk WeakReference<Callbacks> mCallbacks;                                                          
 137                                                                                                          
 138     // < only access in worker thread >                                                                  
 139     AllAppsList mBgAllAppsList;                                                                          
 140     // Entire list of widgets.                                                                           
 141     WidgetsModel mBgWidgetsModel;                                                                        
 142                                                                                                          
 143     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 144     // other locks, this one can generally be held long-term because we never expect any of these        
 145     // static data structures to be referenced outside of the worker thread except on the first          
 146     // load after configuration change.                                                                  
 147     static final Object sBgLock = new Object();                                                          
 148                                                                                                          
 149     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 150     // LauncherModel to their ids                                                                        
 151     static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();                            
 152                                                                                                          
 153     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 154     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 155     //       shortcuts within folders).                                                                  
 156     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 157                                                                                                          
 158     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 159     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 160         new ArrayList<LauncherAppWidgetInfo>();                                                          
 161                                                                                                          
 162     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 163     static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();                             
 164                                                                                                          
 165     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 166     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 167                                                                                                          
 168     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 169     public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;               
 170                                                                                                          
 171     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 172     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                           
 173             new HashMap<UserHandleCompat, HashSet<String>>();                                            
 174                                                                                                          
 175     // </ only access in worker thread >                                                                 
 176                                                                                                          
 177     @Thunk IconCache mIconCache;                                                                         
 178                                                                                                          
 179     @Thunk final LauncherAppsCompat mLauncherApps;                                                       
 180     @Thunk final UserManagerCompat mUserManager;                                                         
 181                                                                                                          
 182     public interface Callbacks {                                                                         
 183         public boolean setLoadOnResume();                                                                
 184         public int getCurrentWorkspaceScreen();                                                          
 185         public void startBinding();                                                                      
 186         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 187                               boolean forceAnimateIcons);                                                
 188         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 189         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 190         public void bindFolders(LongArrayMap<FolderInfo> folders);                                       
 191         public void finishBindingItems();                                                                
 192         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 193         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 194         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 195                                   ArrayList<ItemInfo> addNotAnimated,                                    
 196                                   ArrayList<ItemInfo> addAnimated,                                       
 197                                   ArrayList<AppInfo> addedApps);                                         
 198         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 199         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                
 200                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                 
 201         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                       
 202         public void bindRestoreItemsChange(HashSet<ItemInfo> updates);                                   
 203         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 204                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                 
 205         public void bindAllPackages(WidgetsModel model);                                                 
 206         public void bindSearchablesChanged();                                                            
 207         public boolean isAllAppsButtonRank(int rank);                                                    
 208         public void onPageBoundSynchronously(int page);                                                  
 209         public void dumpLogsToLocalData();                                                               
 210     }                                                                                                    
 211                                                                                                          
 212     public interface ItemInfoFilter {                                                                    
 213         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 214     }                                                                                                    
 215                                                                                                          
 216     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 217         Context context = app.getContext();                                                              
 218                                                                                                          
 219         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 220         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 221         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 222         // resource string.                                                                              
 223         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 224         ProviderInfo providerInfo =                                                                      
 225                 context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                
 226         ProviderInfo redirectProvider =                                                                  
 227                 context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                
 228                                                                                                          
 229         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 230         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 231                                                                                                          
 232         if (mOldContentProviderExists) {                                                                 
 233             Log.d(TAG, "Old launcher provider exists.");                                                 
 234         } else {                                                                                         
 235             Log.d(TAG, "Old launcher provider does not exist.");                                         
 236         }                                                                                                
 237                                                                                                          
 238         mApp = app;                                                                                      
 239         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 240         mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);                               
 241         mIconCache = iconCache;                                                                          
 242                                                                                                          
 243         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 244         mUserManager = UserManagerCompat.getInstance(context);                                           
 245     }                                                                                                    
 246                                                                                                          
 247     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 248      * posted on the main thread handler. */                                                             
 249     @Thunk void runOnMainThread(Runnable r) {                                                            
 250         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 251             // If we are on the worker thread, post onto the main handler                                
 252             mHandler.post(r);                                                                            
 253         } else {                                                                                         
 254             r.run();                                                                                     
 255         }                                                                                                
 256     }                                                                                                    
 257                                                                                                          
 258     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 259      * posted on the worker thread handler. */                                                           
 260     private static void runOnWorkerThread(Runnable r) {                                                  
 261         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 262             r.run();                                                                                     
 263         } else {                                                                                         
 264             // If we are not on the worker thread, then post to the worker handler                       
 265             sWorker.post(r);                                                                             
 266         }                                                                                                
 267     }                                                                                                    
 268                                                                                                          
 269     /**                                                                                                  
 270      * Runs the specified runnable after the loader is complete                                          
 271      */                                                                                                  
 272     @Thunk void runAfterBindCompletes(Runnable r) {                                                      
 273         if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) {                                          
 274             synchronized (mBindCompleteRunnables) {                                                      
 275                 mBindCompleteRunnables.add(r);                                                           
 276             }                                                                                            
 277         } else {                                                                                         
 278             runOnWorkerThread(r);                                                                        
 279         }                                                                                                
 280     }                                                                                                    
 281                                                                                                          
 282     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 283         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 284     }                                                                                                    
 285                                                                                                          
 286     public void setPackageState(final PackageInstallInfo installInfo) {                                  
 287         Runnable updateRunnable = new Runnable() {                                                       
 288                                                                                                          
 289             @Override                                                                                    
 290             public void run() {                                                                          
 291                 synchronized (sBgLock) {                                                                 
 292                     final HashSet<ItemInfo> updates = new HashSet<>();                                   
 293                                                                                                          
 294                     if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                  
 295                         // Ignore install success events as they are handled by Package add events.      
 296                         return;                                                                          
 297                     }                                                                                    
 298                                                                                                          
 299                     for (ItemInfo info : sBgItemsIdMap) {                                                
 300                         if (info instanceof ShortcutInfo) {                                              
 301                             ShortcutInfo si = (ShortcutInfo) info;                                       
 302                             ComponentName cn = si.getTargetComponent();                                  
 303                             if (si.isPromise() && (cn != null)                                           
 304                                     && installInfo.packageName.equals(cn.getPackageName())) {            
 305                                 si.setInstallProgress(installInfo.progress);                             
 306                                                                                                          
 307                                 if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {         
 308                                     // Mark this info as broken.                                         
 309                                     si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;              
 310                                 }                                                                        
 311                                 updates.add(si);                                                         
 312                             }                                                                            
 313                         }                                                                                
 314                     }                                                                                    
 315                                                                                                          
 316                     for (LauncherAppWidgetInfo widget : sBgAppWidgets) {                                 
 317                         if (widget.providerName.getPackageName().equals(installInfo.packageName)) {      
 318                             widget.installProgress = installInfo.progress;                               
 319                             updates.add(widget);                                                         
 320                         }                                                                                
 321                     }                                                                                    
 322                                                                                                          
 323                     if (!updates.isEmpty()) {                                                            
 324                         // Push changes to the callback.                                                 
 325                         Runnable r = new Runnable() {                                                    
 326                             public void run() {                                                          
 327                                 Callbacks callbacks = getCallback();                                     
 328                                 if (callbacks != null) {                                                 
 329                                     callbacks.bindRestoreItemsChange(updates);                           
 330                                 }                                                                        
 331                             }                                                                            
 332                         };                                                                               
 333                         mHandler.post(r);                                                                
 334                     }                                                                                    
 335                 }                                                                                        
 336             }                                                                                            
 337         };                                                                                               
 338         runOnWorkerThread(updateRunnable);                                                               
 339     }                                                                                                    
 340                                                                                                          
 341     /**                                                                                                  
 342      * Updates the icons and label of all pending icons for the provided package name.                   
 343      */                                                                                                  
 344     public void updateSessionDisplayInfo(final String packageName) {                                     
 345         Runnable updateRunnable = new Runnable() {                                                       
 346                                                                                                          
 347             @Override                                                                                    
 348             public void run() {                                                                          
 349                 synchronized (sBgLock) {                                                                 
 350                     final ArrayList<ShortcutInfo> updates = new ArrayList<>();                           
 351                     final UserHandleCompat user = UserHandleCompat.myUserHandle();                       
 352                                                                                                          
 353                     for (ItemInfo info : sBgItemsIdMap) {                                                
 354                         if (info instanceof ShortcutInfo) {                                              
 355                             ShortcutInfo si = (ShortcutInfo) info;                                       
 356                             ComponentName cn = si.getTargetComponent();                                  
 357                             if (si.isPromise() && (cn != null)                                           
 358                                     && packageName.equals(cn.getPackageName())) {                        
 359                                 if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {               
 360                                     // For auto install apps update the icon as well as label.           
 361                                     mIconCache.getTitleAndIcon(si,                                       
 362                                             si.promisedIntent, user,                                     
 363                                             si.shouldUseLowResIcon());                                   
 364                                 } else {                                                                 
 365                                     // Only update the icon for restored apps.                           
 366                                     si.updateIcon(mIconCache);                                           
 367                                 }                                                                        
 368                                 updates.add(si);                                                         
 369                             }                                                                            
 370                         }                                                                                
 371                     }                                                                                    
 372                                                                                                          
 373                     if (!updates.isEmpty()) {                                                            
 374                         // Push changes to the callback.                                                 
 375                         Runnable r = new Runnable() {                                                    
 376                             public void run() {                                                          
 377                                 Callbacks callbacks = getCallback();                                     
 378                                 if (callbacks != null) {                                                 
 379                                     callbacks.bindShortcutsChanged(updates,                              
 380                                             new ArrayList<ShortcutInfo>(), user);                        
 381                                 }                                                                        
 382                             }                                                                            
 383                         };                                                                               
 384                         mHandler.post(r);                                                                
 385                     }                                                                                    
 386                 }                                                                                        
 387             }                                                                                            
 388         };                                                                                               
 389         runOnWorkerThread(updateRunnable);                                                               
 390     }                                                                                                    
 391                                                                                                          
 392     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 393         final Callbacks callbacks = getCallback();                                                       
 394                                                                                                          
 395         if (allAppsApps == null) {                                                                       
 396             throw new RuntimeException("allAppsApps must not be null");                                  
 397         }                                                                                                
 398         if (allAppsApps.isEmpty()) {                                                                     
 399             return;                                                                                      
 400         }                                                                                                
 401                                                                                                          
 402         // Process the newly added applications and add them to the database first                       
 403         Runnable r = new Runnable() {                                                                    
 404             public void run() {                                                                          
 405                 runOnMainThread(new Runnable() {                                                         
 406                     public void run() {                                                                  
 407                         Callbacks cb = getCallback();                                                    
 408                         if (callbacks == cb && cb != null) {                                             
 409                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 410                         }                                                                                
 411                     }                                                                                    
 412                 });                                                                                      
 413             }                                                                                            
 414         };                                                                                               
 415         runOnWorkerThread(r);                                                                            
 416     }                                                                                                    
 417                                                                                                          
 418     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,           
 419             int[] xy, int spanX, int spanY) {                                                            
 420         LauncherAppState app = LauncherAppState.getInstance();                                           
 421         InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                
 422         final int xCount = (int) profile.numColumns;                                                     
 423         final int yCount = (int) profile.numRows;                                                        
 424         boolean[][] occupied = new boolean[xCount][yCount];                                              
 425         if (occupiedPos != null) {                                                                       
 426             for (ItemInfo r : occupiedPos) {                                                             
 427                 int right = r.cellX + r.spanX;                                                           
 428                 int bottom = r.cellY + r.spanY;                                                          
 429                 for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {                          
 430                     for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {                     
 431                         occupied[x][y] = true;                                                           
 432                     }                                                                                    
 433                 }                                                                                        
 434             }                                                                                            
 435         }                                                                                                
 436         return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                     
 437     }                                                                                                    
 438                                                                                                          
 439     /**                                                                                                  
 440      * Find a position on the screen for the given size or adds a new screen.                            
 441      * @return screenId and the coordinates for the item.                                                
 442      */                                                                                                  
 443     @Thunk Pair<Long, int[]> findSpaceForItem(                                                           
 444             Context context,                                                                             
 445             ArrayList<Long> workspaceScreens,                                                            
 446             ArrayList<Long> addedWorkspaceScreensFinal,                                                  
 447             int spanX, int spanY) {                                                                      
 448         LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();                      
 449                                                                                                          
 450         // Use sBgItemsIdMap as all the items are already loaded.                                        
 451         assertWorkspaceLoaded();                                                                         
 452         synchronized (sBgLock) {                                                                         
 453             for (ItemInfo info : sBgItemsIdMap) {                                                        
 454                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
 455                     ArrayList<ItemInfo> items = screenItems.get(info.screenId);                          
 456                     if (items == null) {                                                                 
 457                         items = new ArrayList<>();                                                       
 458                         screenItems.put(info.screenId, items);                                           
 459                     }                                                                                    
 460                     items.add(info);                                                                     
 461                 }                                                                                        
 462             }                                                                                            
 463         }                                                                                                
 464                                                                                                          
 465         // Find appropriate space for the item.                                                          
 466         long screenId = 0;                                                                               
 467         int[] cordinates = new int[2];                                                                   
 468         boolean found = false;                                                                           
 469                                                                                                          
 470         int screenCount = workspaceScreens.size();                                                       
 471         // First check the preferred screen.                                                             
 472         int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;                                   
 473         if (preferredScreenIndex < screenCount) {                                                        
 474             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 475             found = findNextAvailableIconSpaceInScreen(                                                  
 476                     screenItems.get(screenId), cordinates, spanX, spanY);                                
 477         }                                                                                                
 478                                                                                                          
 479         if (!found) {                                                                                    
 480             // Search on any of the screens starting from the first screen.                              
 481             for (int screen = 1; screen < screenCount; screen++) {                                       
 482                 screenId = workspaceScreens.get(screen);                                                 
 483                 if (findNextAvailableIconSpaceInScreen(                                                  
 484                         screenItems.get(screenId), cordinates, spanX, spanY)) {                          
 485                     // We found a space for it                                                           
 486                     found = true;                                                                        
 487                     break;                                                                               
 488                 }                                                                                        
 489             }                                                                                            
 490         }                                                                                                
 491                                                                                                          
 492         if (!found) {                                                                                    
 493             // Still no position found. Add a new screen to the end.                                     
 494             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 495                                                                                                          
 496             // Save the screen id for binding in the workspace                                           
 497             workspaceScreens.add(screenId);                                                              
 498             addedWorkspaceScreensFinal.add(screenId);                                                    
 499                                                                                                          
 500             // If we still can't find an empty space, then God help us all!!!                            
 501             if (!findNextAvailableIconSpaceInScreen(                                                     
 502                     screenItems.get(screenId), cordinates, spanX, spanY)) {                              
 503                 throw new RuntimeException("Can't find space to add the item");                          
 504             }                                                                                            
 505         }                                                                                                
 506         return Pair.create(screenId, cordinates);                                                        
 507     }                                                                                                    
 508                                                                                                          
 509     /**                                                                                                  
 510      * Adds the provided items to the workspace.                                                         
 511      */                                                                                                  
 512     public void addAndBindAddedWorkspaceItems(final Context context,                                     
 513             final ArrayList<? extends ItemInfo> workspaceApps) {                                         
 514         final Callbacks callbacks = getCallback();                                                       
 515         if (workspaceApps.isEmpty()) {                                                                   
 516             return;                                                                                      
 517         }                                                                                                
 518         // Process the newly added applications and add them to the database first                       
 519         Runnable r = new Runnable() {                                                                    
 520             public void run() {                                                                          
 521                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 522                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 523                                                                                                          
 524                 // Get the list of workspace screens.  We need to append to this list and                
 525                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 526                 // called.                                                                               
 527                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 528                 synchronized(sBgLock) {                                                                  
 529                     for (ItemInfo item : workspaceApps) {                                                
 530                         if (item instanceof ShortcutInfo) {                                              
 531                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 532                             if (shortcutExists(context, item.getIntent(), item.user)) {                  
 533                                 continue;                                                                
 534                             }                                                                            
 535                         }                                                                                
 536                                                                                                          
 537                         // Find appropriate space for the item.                                          
 538                         Pair<Long, int[]> coords = findSpaceForItem(context,                             
 539                                 workspaceScreens, addedWorkspaceScreensFinal,                            
 540                                 1, 1);                                                                   
 541                         long screenId = coords.first;                                                    
 542                         int[] cordinates = coords.second;                                                
 543                                                                                                          
 544                         ItemInfo itemInfo;                                                               
 545                         if (item instanceof ShortcutInfo || item instanceof FolderInfo) {                
 546                             itemInfo = item;                                                             
 547                         } else if (item instanceof AppInfo) {                                            
 548                             itemInfo = ((AppInfo) item).makeShortcut();                                  
 549                         } else {                                                                         
 550                             throw new RuntimeException("Unexpected info type");                          
 551                         }                                                                                
 552                                                                                                          
 553                         // Add the shortcut to the db                                                    
 554                         addItemToDatabase(context, itemInfo,                                             
 555                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 556                                 screenId, cordinates[0], cordinates[1]);                                 
 557                         // Save the ShortcutInfo for binding in the workspace                            
 558                         addedShortcutsFinal.add(itemInfo);                                               
 559                     }                                                                                    
 560                 }                                                                                        
 561                                                                                                          
 562                 // Update the workspace screens                                                          
 563                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 564                                                                                                          
 565                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 566                     runOnMainThread(new Runnable() {                                                     
 567                         public void run() {                                                              
 568                             Callbacks cb = getCallback();                                                
 569                             if (callbacks == cb && cb != null) {                                         
 570                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 571                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 572                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 573                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 574                                     long lastScreenId = info.screenId;                                   
 575                                     for (ItemInfo i : addedShortcutsFinal) {                             
 576                                         if (i.screenId == lastScreenId) {                                
 577                                             addAnimated.add(i);                                          
 578                                         } else {                                                         
 579                                             addNotAnimated.add(i);                                       
 580                                         }                                                                
 581                                     }                                                                    
 582                                 }                                                                        
 583                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 584                                         addNotAnimated, addAnimated, null);                              
 585                             }                                                                            
 586                         }                                                                                
 587                     });                                                                                  
 588                 }                                                                                        
 589             }                                                                                            
 590         };                                                                                               
 591         runOnWorkerThread(r);                                                                            
 592     }                                                                                                    
 593                                                                                                          
 594     private void unbindItemInfosAndClearQueuedBindRunnables() {                                          
 595         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 596             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 597                     "main thread");                                                                      
 598         }                                                                                                
 599                                                                                                          
 600         // Clear any deferred bind runnables                                                             
 601         synchronized (mDeferredBindRunnables) {                                                          
 602             mDeferredBindRunnables.clear();                                                              
 603         }                                                                                                
 604                                                                                                          
 605         // Remove any queued UI runnables                                                                
 606         mHandler.cancelAll();                                                                            
 607         // Unbind all the workspace items                                                                
 608         unbindWorkspaceItemsOnMainThread();                                                              
 609     }                                                                                                    
 610                                                                                                          
 611     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 612     void unbindWorkspaceItemsOnMainThread() {                                                            
 613         // Ensure that we don't use the same workspace items data structure on the main thread           
 614         // by making a copy of workspace items first.                                                    
 615         final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();                                  
 616         synchronized (sBgLock) {                                                                         
 617             tmpItems.addAll(sBgWorkspaceItems);                                                          
 618             tmpItems.addAll(sBgAppWidgets);                                                              
 619         }                                                                                                
 620         Runnable r = new Runnable() {                                                                    
 621                 @Override                                                                                
 622                 public void run() {                                                                      
 623                    for (ItemInfo item : tmpItems) {                                                      
 624                        item.unbind();                                                                    
 625                    }                                                                                     
 626                 }                                                                                        
 627             };                                                                                           
 628         runOnMainThread(r);                                                                              
 629     }                                                                                                    
 630                                                                                                          
 631     /**                                                                                                  
 632      * Adds an item to the DB if it was not created previously, or move it to a new                      
 633      * <container, screen, cellX, cellY>                                                                 
 634      */                                                                                                  
 635     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 636             long screenId, int cellX, int cellY) {                                                       
 637         if (item.container == ItemInfo.NO_ID) {                                                          
 638             // From all apps                                                                             
 639             addItemToDatabase(context, item, container, screenId, cellX, cellY);                         
 640         } else {                                                                                         
 641             // From somewhere else                                                                       
 642             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 643         }                                                                                                
 644     }                                                                                                    
 645                                                                                                          
 646     static void checkItemInfoLocked(                                                                     
 647             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 648         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 649         if (modelItem != null && item != modelItem) {                                                    
 650             // check all the data is consistent                                                          
 651             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 652                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 653                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 654                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 655                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 656                         modelShortcut.id == shortcut.id &&                                               
 657                         modelShortcut.itemType == shortcut.itemType &&                                   
 658                         modelShortcut.container == shortcut.container &&                                 
 659                         modelShortcut.screenId == shortcut.screenId &&                                   
 660                         modelShortcut.cellX == shortcut.cellX &&                                         
 661                         modelShortcut.cellY == shortcut.cellY &&                                         
 662                         modelShortcut.spanX == shortcut.spanX &&                                         
 663                         modelShortcut.spanY == shortcut.spanY &&                                         
 664                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 665                         (modelShortcut.dropPos != null &&                                                
 666                                 shortcut.dropPos != null &&                                              
 667                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 668                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 669                     // For all intents and purposes, this is the same object                             
 670                     return;                                                                              
 671                 }                                                                                        
 672             }                                                                                            
 673                                                                                                          
 674             // the modelItem needs to match up perfectly with item if our model is                       
 675             // to be consistent with the database-- for now, just require                                
 676             // modelItem == item or the equality check above                                             
 677             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 678                     "modelItem: " +                                                                      
 679                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 680                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 681             RuntimeException e = new RuntimeException(msg);                                              
 682             if (stackTrace != null) {                                                                    
 683                 e.setStackTrace(stackTrace);                                                             
 684             }                                                                                            
 685             throw e;                                                                                     
 686         }                                                                                                
 687     }                                                                                                    
 688                                                                                                          
 689     static void checkItemInfo(final ItemInfo item) {                                                     
 690         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 691         final long itemId = item.id;                                                                     
 692         Runnable r = new Runnable() {                                                                    
 693             public void run() {                                                                          
 694                 synchronized (sBgLock) {                                                                 
 695                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 696                 }                                                                                        
 697             }                                                                                            
 698         };                                                                                               
 699         runOnWorkerThread(r);                                                                            
 700     }                                                                                                    
 701                                                                                                          
 702     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 703             final ItemInfo item, final String callingFunction) {                                         
 704         final long itemId = item.id;                                                                     
 705         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                                
 706         final ContentResolver cr = context.getContentResolver();                                         
 707                                                                                                          
 708         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 709         Runnable r = new Runnable() {                                                                    
 710             public void run() {                                                                          
 711                 cr.update(uri, values, null, null);                                                      
 712                 updateItemArrays(item, itemId, stackTrace);                                              
 713             }                                                                                            
 714         };                                                                                               
 715         runOnWorkerThread(r);                                                                            
 716     }                                                                                                    
 717                                                                                                          
 718     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 719             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 720         final ContentResolver cr = context.getContentResolver();                                         
 721                                                                                                          
 722         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 723         Runnable r = new Runnable() {                                                                    
 724             public void run() {                                                                          
 725                 ArrayList<ContentProviderOperation> ops =                                                
 726                         new ArrayList<ContentProviderOperation>();                                       
 727                 int count = items.size();                                                                
 728                 for (int i = 0; i < count; i++) {                                                        
 729                     ItemInfo item = items.get(i);                                                        
 730                     final long itemId = item.id;                                                         
 731                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                    
 732                     ContentValues values = valuesList.get(i);                                            
 733                                                                                                          
 734                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 735                     updateItemArrays(item, itemId, stackTrace);                                          
 736                                                                                                          
 737                 }                                                                                        
 738                 try {                                                                                    
 739                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 740                 } catch (Exception e) {                                                                  
 741                     e.printStackTrace();                                                                 
 742                 }                                                                                        
 743             }                                                                                            
 744         };                                                                                               
 745         runOnWorkerThread(r);                                                                            
 746     }                                                                                                    
 747                                                                                                          
 748     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 749         // Lock on mBgLock *after* the db operation                                                      
 750         synchronized (sBgLock) {                                                                         
 751             checkItemInfoLocked(itemId, item, stackTrace);                                               
 752                                                                                                          
 753             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 754                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 755                 // Item is in a folder, make sure this folder exists                                     
 756                 if (!sBgFolders.containsKey(item.container)) {                                           
 757                     // An items container is being set to a that of an item which is not in              
 758                     // the list of Folders.                                                              
 759                     String msg = "item: " + item + " container being set to: " +                         
 760                             item.container + ", not in the list of folders";                             
 761                     Log.e(TAG, msg);                                                                     
 762                 }                                                                                        
 763             }                                                                                            
 764                                                                                                          
 765             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 766             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 767             // that are on the desktop, as appropriate                                                   
 768             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 769             if (modelItem != null &&                                                                     
 770                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 771                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 772                 switch (modelItem.itemType) {                                                            
 773                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 774                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 775                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 776                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 777                             sBgWorkspaceItems.add(modelItem);                                            
 778                         }                                                                                
 779                         break;                                                                           
 780                     default:                                                                             
 781                         break;                                                                           
 782                 }                                                                                        
 783             } else {                                                                                     
 784                 sBgWorkspaceItems.remove(modelItem);                                                     
 785             }                                                                                            
 786         }                                                                                                
 787     }                                                                                                    
 788                                                                                                          
 789     /**                                                                                                  
 790      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 791      */                                                                                                  
 792     public static void moveItemInDatabase(Context context, final ItemInfo item, final long container,    
 793             final long screenId, final int cellX, final int cellY) {                                     
 794         item.container = container;                                                                      
 795         item.cellX = cellX;                                                                              
 796         item.cellY = cellY;                                                                              
 797                                                                                                          
 798         // We store hotseat items in canonical form which is this orientation invariant position         
 799         // in the hotseat                                                                                
 800         if (context instanceof Launcher && screenId < 0 &&                                               
 801                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 802             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 803         } else {                                                                                         
 804             item.screenId = screenId;                                                                    
 805         }                                                                                                
 806                                                                                                          
 807         final ContentValues values = new ContentValues();                                                
 808         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 809         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 810         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 811         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 812         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 813                                                                                                          
 814         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 815     }                                                                                                    
 816                                                                                                          
 817     /**                                                                                                  
 818      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 819      * cellX, cellY have already been updated on the ItemInfos.                                          
 820      */                                                                                                  
 821     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 822             final long container, final int screen) {                                                    
 823                                                                                                          
 824         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 825         int count = items.size();                                                                        
 826                                                                                                          
 827         for (int i = 0; i < count; i++) {                                                                
 828             ItemInfo item = items.get(i);                                                                
 829             item.container = container;                                                                  
 830                                                                                                          
 831             // We store hotseat items in canonical form which is this orientation invariant position     
 832             // in the hotseat                                                                            
 833             if (context instanceof Launcher && screen < 0 &&                                             
 834                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 835                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 836                         item.cellY);                                                                     
 837             } else {                                                                                     
 838                 item.screenId = screen;                                                                  
 839             }                                                                                            
 840                                                                                                          
 841             final ContentValues values = new ContentValues();                                            
 842             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 843             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 844             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 845             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 846             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 847                                                                                                          
 848             contentValues.add(values);                                                                   
 849         }                                                                                                
 850         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 851     }                                                                                                    
 852                                                                                                          
 853     /**                                                                                                  
 854      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 855      */                                                                                                  
 856     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 857             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 858         item.container = container;                                                                      
 859         item.cellX = cellX;                                                                              
 860         item.cellY = cellY;                                                                              
 861         item.spanX = spanX;                                                                              
 862         item.spanY = spanY;                                                                              
 863                                                                                                          
 864         // We store hotseat items in canonical form which is this orientation invariant position         
 865         // in the hotseat                                                                                
 866         if (context instanceof Launcher && screenId < 0 &&                                               
 867                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 868             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 869         } else {                                                                                         
 870             item.screenId = screenId;                                                                    
 871         }                                                                                                
 872                                                                                                          
 873         final ContentValues values = new ContentValues();                                                
 874         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 875         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 876         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 877         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 878         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 879         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 880         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 881                                                                                                          
 882         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 883     }                                                                                                    
 884                                                                                                          
 885     /**                                                                                                  
 886      * Update an item to the database in a specified container.                                          
 887      */                                                                                                  
 888     public static void updateItemInDatabase(Context context, final ItemInfo item) {                      
 889         final ContentValues values = new ContentValues();                                                
 890         item.onAddToDatabase(context, values);                                                           
 891         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 892     }                                                                                                    
 893                                                                                                          
 894     private void assertWorkspaceLoaded() {                                                               
 895         if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) {   
 896             throw new RuntimeException("Trying to add shortcut while loader is running");                
 897         }                                                                                                
 898     }                                                                                                    
 899                                                                                                          
 900     /**                                                                                                  
 901      * Returns true if the shortcuts already exists on the workspace. This must be called after          
 902      * the workspace has been loaded. We identify a shortcut by its intent.                              
 903      */                                                                                                  
 904     @Thunk boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {               
 905         assertWorkspaceLoaded();                                                                         
 906         final String intentWithPkg, intentWithoutPkg;                                                    
 907         if (intent.getComponent() != null) {                                                             
 908             // If component is not null, an intent with null package will produce                        
 909             // the same result and should also be a match.                                               
 910             String packageName = intent.getComponent().getPackageName();                                 
 911             if (intent.getPackage() != null) {                                                           
 912                 intentWithPkg = intent.toUri(0);                                                         
 913                 intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);                         
 914             } else {                                                                                     
 915                 intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);                     
 916                 intentWithoutPkg = intent.toUri(0);                                                      
 917             }                                                                                            
 918         } else {                                                                                         
 919             intentWithPkg = intent.toUri(0);                                                             
 920             intentWithoutPkg = intent.toUri(0);                                                          
 921         }                                                                                                
 922                                                                                                          
 923         synchronized (sBgLock) {                                                                         
 924             for (ItemInfo item : sBgItemsIdMap) {                                                        
 925                 if (item instanceof ShortcutInfo) {                                                      
 926                     ShortcutInfo info = (ShortcutInfo) item;                                             
 927                     Intent targetIntent = info.promisedIntent == null                                    
 928                             ? info.intent : info.promisedIntent;                                         
 929                     if (targetIntent != null && info.user.equals(user)) {                                
 930                         String s = targetIntent.toUri(0);                                                
 931                         if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {                     
 932                             return true;                                                                 
 933                         }                                                                                
 934                     }                                                                                    
 935                 }                                                                                        
 936             }                                                                                            
 937         }                                                                                                
 938         return false;                                                                                    
 939     }                                                                                                    
 940                                                                                                          
 941     /**                                                                                                  
 942      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 943      */                                                                                                  
 944     FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {            
 945         final ContentResolver cr = context.getContentResolver();                                         
 946         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 947                 "_id=? and (itemType=? or itemType=?)",                                                  
 948                 new String[] { String.valueOf(id),                                                       
 949                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 950                                                                                                          
 951         try {                                                                                            
 952             if (c.moveToFirst()) {                                                                       
 953                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 954                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 955                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 956                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 957                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 958                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 959                 final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);    
 960                                                                                                          
 961                 FolderInfo folderInfo = null;                                                            
 962                 switch (c.getInt(itemTypeIndex)) {                                                       
 963                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 964                         folderInfo = findOrMakeFolder(folderList, id);                                   
 965                         break;                                                                           
 966                 }                                                                                        
 967                                                                                                          
 968                 // Do not trim the folder label, as is was set by the user.                              
 969                 folderInfo.title = c.getString(titleIndex);                                              
 970                 folderInfo.id = id;                                                                      
 971                 folderInfo.container = c.getInt(containerIndex);                                         
 972                 folderInfo.screenId = c.getInt(screenIndex);                                             
 973                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 974                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 975                 folderInfo.options = c.getInt(optionsIndex);                                             
 976                                                                                                          
 977                 return folderInfo;                                                                       
 978             }                                                                                            
 979         } finally {                                                                                      
 980             c.close();                                                                                   
 981         }                                                                                                
 982                                                                                                          
 983         return null;                                                                                     
 984     }                                                                                                    
 985                                                                                                          
 986     /**                                                                                                  
 987      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 988      * cellY fields of the item. Also assigns an ID to the item.                                         
 989      */                                                                                                  
 990     public static void addItemToDatabase(Context context, final ItemInfo item, final long container,     
 991             final long screenId, final int cellX, final int cellY) {                                     
 992         item.container = container;                                                                      
 993         item.cellX = cellX;                                                                              
 994         item.cellY = cellY;                                                                              
 995         // We store hotseat items in canonical form which is this orientation invariant position         
 996         // in the hotseat                                                                                
 997         if (context instanceof Launcher && screenId < 0 &&                                               
 998                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 999             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1000         } else {                                                                                         
1001             item.screenId = screenId;                                                                    
1002         }                                                                                                
1003                                                                                                          
1004         final ContentValues values = new ContentValues();                                                
1005         final ContentResolver cr = context.getContentResolver();                                         
1006         item.onAddToDatabase(context, values);                                                           
1007                                                                                                          
1008         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1009         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1010                                                                                                          
1011         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
1012         Runnable r = new Runnable() {                                                                    
1013             public void run() {                                                                          
1014                 cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);                               
1015                                                                                                          
1016                 // Lock on mBgLock *after* the db operation                                              
1017                 synchronized (sBgLock) {                                                                 
1018                     checkItemInfoLocked(item.id, item, stackTrace);                                      
1019                     sBgItemsIdMap.put(item.id, item);                                                    
1020                     switch (item.itemType) {                                                             
1021                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1022                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1023                             // Fall through                                                              
1024                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1025                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1026                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1027                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1028                                 sBgWorkspaceItems.add(item);                                             
1029                             } else {                                                                     
1030                                 if (!sBgFolders.containsKey(item.container)) {                           
1031                                     // Adding an item to a folder that doesn't exist.                    
1032                                     String msg = "adding item: " + item + " to a folder that " +         
1033                                             " doesn't exist";                                            
1034                                     Log.e(TAG, msg);                                                     
1035                                 }                                                                        
1036                             }                                                                            
1037                             break;                                                                       
1038                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1039                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1040                             break;                                                                       
1041                     }                                                                                    
1042                 }                                                                                        
1043             }                                                                                            
1044         };                                                                                               
1045         runOnWorkerThread(r);                                                                            
1046     }                                                                                                    
1047                                                                                                          
1048     /**                                                                                                  
1049      * Creates a new unique child id, for a given cell span across all layouts.                          
1050      */                                                                                                  
1051     static int getCellLayoutChildId(                                                                     
1052             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1053         return (((int) container & 0xFF) << 24)                                                          
1054                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1055     }                                                                                                    
1056                                                                                                          
1057     private static ArrayList<ItemInfo> getItemsByPackageName(                                            
1058             final String pn, final UserHandleCompat user) {                                              
1059         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
1060             @Override                                                                                    
1061             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1062                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1063             }                                                                                            
1064         };                                                                                               
1065         return filterItemInfos(sBgItemsIdMap, filter);                                                   
1066     }                                                                                                    
1067                                                                                                          
1068     /**                                                                                                  
1069      * Removes all the items from the database corresponding to the specified package.                   
1070      */                                                                                                  
1071     static void deletePackageFromDatabase(Context context, final String pn,                              
1072             final UserHandleCompat user) {                                                               
1073         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1074     }                                                                                                    
1075                                                                                                          
1076     /**                                                                                                  
1077      * Removes the specified item from the database                                                      
1078      * @param context                                                                                    
1079      * @param item                                                                                       
1080      */                                                                                                  
1081     public static void deleteItemFromDatabase(Context context, final ItemInfo item) {                    
1082         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1083         items.add(item);                                                                                 
1084         deleteItemsFromDatabase(context, items);                                                         
1085     }                                                                                                    
1086                                                                                                          
1087     /**                                                                                                  
1088      * Removes the specified items from the database                                                     
1089      * @param context                                                                                    
1090      * @param item                                                                                       
1091      */                                                                                                  
1092     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1093         final ContentResolver cr = context.getContentResolver();                                         
1094         Runnable r = new Runnable() {                                                                    
1095             public void run() {                                                                          
1096                 for (ItemInfo item : items) {                                                            
1097                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);                   
1098                     cr.delete(uri, null, null);                                                          
1099                                                                                                          
1100                     // Lock on mBgLock *after* the db operation                                          
1101                     synchronized (sBgLock) {                                                             
1102                         switch (item.itemType) {                                                         
1103                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
1104                                 sBgFolders.remove(item.id);                                              
1105                                 for (ItemInfo info: sBgItemsIdMap) {                                     
1106                                     if (info.container == item.id) {                                     
1107                                         // We are deleting a folder which still contains items that      
1108                                         // think they are contained by that folder.                      
1109                                         String msg = "deleting a folder (" + item + ") which still " +   
1110                                                 "contains items (" + info + ")";                         
1111                                         Log.e(TAG, msg);                                                 
1112                                     }                                                                    
1113                                 }                                                                        
1114                                 sBgWorkspaceItems.remove(item);                                          
1115                                 break;                                                                   
1116                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1117                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1118                                 sBgWorkspaceItems.remove(item);                                          
1119                                 break;                                                                   
1120                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
1121                                 sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                      
1122                                 break;                                                                   
1123                         }                                                                                
1124                         sBgItemsIdMap.remove(item.id);                                                   
1125                     }                                                                                    
1126                 }                                                                                        
1127             }                                                                                            
1128         };                                                                                               
1129         runOnWorkerThread(r);                                                                            
1130     }                                                                                                    
1131                                                                                                          
1132     /**                                                                                                  
1133      * Update the order of the workspace screens in the database. The array list contains                
1134      * a list of screen ids in the order that they should appear.                                        
1135      */                                                                                                  
1136     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1137         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1138         final ContentResolver cr = context.getContentResolver();                                         
1139         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1140                                                                                                          
1141         // Remove any negative screen ids -- these aren't persisted                                      
1142         Iterator<Long> iter = screensCopy.iterator();                                                    
1143         while (iter.hasNext()) {                                                                         
1144             long id = iter.next();                                                                       
1145             if (id < 0) {                                                                                
1146                 iter.remove();                                                                           
1147             }                                                                                            
1148         }                                                                                                
1149                                                                                                          
1150         Runnable r = new Runnable() {                                                                    
1151             @Override                                                                                    
1152             public void run() {                                                                          
1153                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1154                 // Clear the table                                                                       
1155                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1156                 int count = screensCopy.size();                                                          
1157                 for (int i = 0; i < count; i++) {                                                        
1158                     ContentValues v = new ContentValues();                                               
1159                     long screenId = screensCopy.get(i);                                                  
1160                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1161                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1162                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1163                 }                                                                                        
1164                                                                                                          
1165                 try {                                                                                    
1166                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1167                 } catch (Exception ex) {                                                                 
1168                     throw new RuntimeException(ex);                                                      
1169                 }                                                                                        
1170                                                                                                          
1171                 synchronized (sBgLock) {                                                                 
1172                     sBgWorkspaceScreens.clear();                                                         
1173                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1174                 }                                                                                        
1175             }                                                                                            
1176         };                                                                                               
1177         runOnWorkerThread(r);                                                                            
1178     }                                                                                                    
1179                                                                                                          
1180     /**                                                                                                  
1181      * Remove the contents of the specified folder from the database                                     
1182      */                                                                                                  
1183     public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {        
1184         final ContentResolver cr = context.getContentResolver();                                         
1185                                                                                                          
1186         Runnable r = new Runnable() {                                                                    
1187             public void run() {                                                                          
1188                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);                
1189                 // Lock on mBgLock *after* the db operation                                              
1190                 synchronized (sBgLock) {                                                                 
1191                     sBgItemsIdMap.remove(info.id);                                                       
1192                     sBgFolders.remove(info.id);                                                          
1193                     sBgWorkspaceItems.remove(info);                                                      
1194                 }                                                                                        
1195                                                                                                          
1196                 cr.delete(LauncherSettings.Favorites.CONTENT_URI,                                        
1197                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1198                 // Lock on mBgLock *after* the db operation                                              
1199                 synchronized (sBgLock) {                                                                 
1200                     for (ItemInfo childInfo : info.contents) {                                           
1201                         sBgItemsIdMap.remove(childInfo.id);                                              
1202                     }                                                                                    
1203                 }                                                                                        
1204             }                                                                                            
1205         };                                                                                               
1206         runOnWorkerThread(r);                                                                            
1207     }                                                                                                    
1208                                                                                                          
1209     /**                                                                                                  
1210      * Set this as the current Launcher activity object for the loader.                                  
1211      */                                                                                                  
1212     public void initialize(Callbacks callbacks) {                                                        
1213         synchronized (mLock) {                                                                           
1214             // Disconnect any of the callbacks and drawables associated with ItemInfos on the            
1215             // workspace to prevent leaking Launcher activities on orientation change.                   
1216             unbindItemInfosAndClearQueuedBindRunnables();                                                
1217             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1218         }                                                                                                
1219     }                                                                                                    
1220                                                                                                          
1221     @Override                                                                                            
1222     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1223         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1224         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1225                 user));                                                                                  
1226     }                                                                                                    
1227                                                                                                          
1228     @Override                                                                                            
1229     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1230         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1231         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1232                 user));                                                                                  
1233     }                                                                                                    
1234                                                                                                          
1235     @Override                                                                                            
1236     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1237         int op = PackageUpdatedTask.OP_ADD;                                                              
1238         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1239                 user));                                                                                  
1240     }                                                                                                    
1241                                                                                                          
1242     @Override                                                                                            
1243     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1244             boolean replacing) {                                                                         
1245         if (!replacing) {                                                                                
1246             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1247                     user));                                                                              
1248             if (mAppsCanBeOnRemoveableStorage) {                                                         
1249                 // Only rebind if we support removable storage. It catches the                           
1250                 // case where                                                                            
1251                 // apps on the external sd card need to be reloaded                                      
1252                 startLoaderFromBackground();                                                             
1253             }                                                                                            
1254         } else {                                                                                         
1255             // If we are replacing then just update the packages in the list                             
1256             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1257                     packageNames, user));                                                                
1258         }                                                                                                
1259     }                                                                                                    
1260                                                                                                          
1261     @Override                                                                                            
1262     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1263             boolean replacing) {                                                                         
1264         if (!replacing) {                                                                                
1265             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1266                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1267                     user));                                                                              
1268         }                                                                                                
1269     }                                                                                                    
1270                                                                                                          
1271     /**                                                                                                  
1272      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1273      * ACTION_PACKAGE_CHANGED.                                                                           
1274      */                                                                                                  
1275     @Override                                                                                            
1276     public void onReceive(Context context, Intent intent) {                                              
1277         if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                    
1278                                                                                                          
1279         final String action = intent.getAction();                                                        
1280         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1281             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1282             forceReload();                                                                               
1283         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1284                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1285             Callbacks callbacks = getCallback();                                                         
1286             if (callbacks != null) {                                                                     
1287                 callbacks.bindSearchablesChanged();                                                      
1288             }                                                                                            
1289         } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)                        
1290                 || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {                   
1291             forceReload();                                                                               
1292         }                                                                                                
1293     }                                                                                                    
1294                                                                                                          
1295     void forceReload() {                                                                                 
1296         resetLoadedState(true, true);                                                                    
1297                                                                                                          
1298         // Do this here because if the launcher activity is running it will be restarted.                
1299         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1300         // to reload.                                                                                    
1301         startLoaderFromBackground();                                                                     
1302     }                                                                                                    
1303                                                                                                          
1304     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1305         synchronized (mLock) {                                                                           
1306             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1307             // mWorkspaceLoaded to true later                                                            
1308             stopLoaderLocked();                                                                          
1309             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1310             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1311         }                                                                                                
1312     }                                                                                                    
1313                                                                                                          
1314     /**                                                                                                  
1315      * When the launcher is in the background, it's possible for it to miss paired                       
1316      * configuration changes.  So whenever we trigger the loader from the background                     
1317      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1318      * of doing it now.                                                                                  
1319      */                                                                                                  
1320     public void startLoaderFromBackground() {                                                            
1321         boolean runLoader = false;                                                                       
1322         Callbacks callbacks = getCallback();                                                             
1323         if (callbacks != null) {                                                                         
1324             // Only actually run the loader if they're not paused.                                       
1325             if (!callbacks.setLoadOnResume()) {                                                          
1326                 runLoader = true;                                                                        
1327             }                                                                                            
1328         }                                                                                                
1329         if (runLoader) {                                                                                 
1330             startLoader(PagedView.INVALID_RESTORE_PAGE);                                                 
1331         }                                                                                                
1332     }                                                                                                    
1333                                                                                                          
1334     /**                                                                                                  
1335      * If there is already a loader task running, tell it to stop.                                       
1336      */                                                                                                  
1337     private void stopLoaderLocked() {                                                                    
1338         LoaderTask oldTask = mLoaderTask;                                                                
1339         if (oldTask != null) {                                                                           
1340             oldTask.stopLocked();                                                                        
1341         }                                                                                                
1342     }                                                                                                    
1343                                                                                                          
1344     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1345         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1346     }                                                                                                    
1347                                                                                                          
1348     public void startLoader(int synchronousBindPage) {                                                   
1349         startLoader(synchronousBindPage, LOADER_FLAG_NONE);                                              
1350     }                                                                                                    
1351                                                                                                          
1352     public void startLoader(int synchronousBindPage, int loadFlags) {                                    
1353         // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems      
1354         InstallShortcutReceiver.enableInstallQueue();                                                    
1355         synchronized (mLock) {                                                                           
1356             // Clear any deferred bind-runnables from the synchronized load process                      
1357             // We must do this before any loading/binding is scheduled below.                            
1358             synchronized (mDeferredBindRunnables) {                                                      
1359                 mDeferredBindRunnables.clear();                                                          
1360             }                                                                                            
1361                                                                                                          
1362             // Don't bother to start the thread if we know it's not going to do anything                 
1363             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1364                 // If there is already one running, tell it to stop.                                     
1365                 stopLoaderLocked();                                                                      
1366                 mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);                              
1367                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1368                         && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {                
1369                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1370                 } else {                                                                                 
1371                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1372                     sWorker.post(mLoaderTask);                                                           
1373                 }                                                                                        
1374             }                                                                                            
1375         }                                                                                                
1376     }                                                                                                    
1377                                                                                                          
1378     void bindRemainingSynchronousPages() {                                                               
1379         // Post the remaining side pages to be loaded                                                    
1380         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1381             Runnable[] deferredBindRunnables = null;                                                     
1382             synchronized (mDeferredBindRunnables) {                                                      
1383                 deferredBindRunnables = mDeferredBindRunnables.toArray(                                  
1384                         new Runnable[mDeferredBindRunnables.size()]);                                    
1385                 mDeferredBindRunnables.clear();                                                          
1386             }                                                                                            
1387             for (final Runnable r : deferredBindRunnables) {                                             
1388                 mHandler.post(r);                                                                        
1389             }                                                                                            
1390         }                                                                                                
1391                                                                                                          
1392         // Run all the bind complete runnables after workspace is bound.                                 
1393         if (!mBindCompleteRunnables.isEmpty()) {                                                         
1394             synchronized (mBindCompleteRunnables) {                                                      
1395                 for (final Runnable r : mBindCompleteRunnables) {                                        
1396                     runOnWorkerThread(r);                                                                
1397                 }                                                                                        
1398                 mBindCompleteRunnables.clear();                                                          
1399             }                                                                                            
1400         }                                                                                                
1401     }                                                                                                    
1402                                                                                                          
1403     public void stopLoader() {                                                                           
1404         synchronized (mLock) {                                                                           
1405             if (mLoaderTask != null) {                                                                   
1406                 mLoaderTask.stopLocked();                                                                
1407             }                                                                                            
1408         }                                                                                                
1409     }                                                                                                    
1410                                                                                                          
1411     /**                                                                                                  
1412      * Loads the workspace screen ids in an ordered list.                                                
1413      */                                                                                                  
1414     @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                              
1415         final ContentResolver contentResolver = context.getContentResolver();                            
1416         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1417                                                                                                          
1418         // Get screens ordered by rank.                                                                  
1419         final Cursor sc = contentResolver.query(screensUri, null, null, null,                            
1420                     LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                      
1421         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1422         try {                                                                                            
1423             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1424             while (sc.moveToNext()) {                                                                    
1425                 try {                                                                                    
1426                     screenIds.add(sc.getLong(idIndex));                                                  
1427                 } catch (Exception e) {                                                                  
1428                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                         
1429                             + " - invalid screens: " + e, true);                                         
1430                 }                                                                                        
1431             }                                                                                            
1432         } finally {                                                                                      
1433             sc.close();                                                                                  
1434         }                                                                                                
1435         return screenIds;                                                                                
1436     }                                                                                                    
1437                                                                                                          
1438     public boolean isAllAppsLoaded() {                                                                   
1439         return mAllAppsLoaded;                                                                           
1440     }                                                                                                    
1441                                                                                                          
1442     boolean isLoadingWorkspace() {                                                                       
1443         synchronized (mLock) {                                                                           
1444             if (mLoaderTask != null) {                                                                   
1445                 return mLoaderTask.isLoadingWorkspace();                                                 
1446             }                                                                                            
1447         }                                                                                                
1448         return false;                                                                                    
1449     }                                                                                                    
1450                                                                                                          
1451     /**                                                                                                  
1452      * Runnable for the thread that loads the contents of the launcher:                                  
1453      *   - workspace icons                                                                               
1454      *   - widgets                                                                                       
1455      *   - all apps icons                                                                                
1456      */                                                                                                  
1457     private class LoaderTask implements Runnable {                                                       
1458         private Context mContext;                                                                        
1459         @Thunk boolean mIsLoadingAndBindingWorkspace;                                                    
1460         private boolean mStopped;                                                                        
1461         @Thunk boolean mLoadAndBindStepFinished;                                                         
1462         private int mFlags;                                                                              
1463                                                                                                          
1464         LoaderTask(Context context, int flags) {                                                         
1465             mContext = context;                                                                          
1466             mFlags = flags;                                                                              
1467         }                                                                                                
1468                                                                                                          
1469         boolean isLoadingWorkspace() {                                                                   
1470             return mIsLoadingAndBindingWorkspace;                                                        
1471         }                                                                                                
1472                                                                                                          
1473         private void loadAndBindWorkspace() {                                                            
1474             mIsLoadingAndBindingWorkspace = true;                                                        
1475                                                                                                          
1476             // Load the workspace                                                                        
1477             if (DEBUG_LOADERS) {                                                                         
1478                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1479             }                                                                                            
1480                                                                                                          
1481             if (!mWorkspaceLoaded) {                                                                     
1482                 loadWorkspace();                                                                         
1483                 synchronized (LoaderTask.this) {                                                         
1484                     if (mStopped) {                                                                      
1485                         return;                                                                          
1486                     }                                                                                    
1487                     mWorkspaceLoaded = true;                                                             
1488                 }                                                                                        
1489             }                                                                                            
1490                                                                                                          
1491             // Bind the workspace                                                                        
1492             bindWorkspace(-1);                                                                           
1493         }                                                                                                
1494                                                                                                          
1495         private void waitForIdle() {                                                                     
1496             // Wait until the either we're stopped or the other threads are done.                        
1497             // This way we don't start loading all apps until the workspace has settled                  
1498             // down.                                                                                     
1499             synchronized (LoaderTask.this) {                                                             
1500                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1501                                                                                                          
1502                 mHandler.postIdle(new Runnable() {                                                       
1503                         public void run() {                                                              
1504                             synchronized (LoaderTask.this) {                                             
1505                                 mLoadAndBindStepFinished = true;                                         
1506                                 if (DEBUG_LOADERS) {                                                     
1507                                     Log.d(TAG, "done with previous binding step");                       
1508                                 }                                                                        
1509                                 LoaderTask.this.notify();                                                
1510                             }                                                                            
1511                         }                                                                                
1512                     });                                                                                  
1513                                                                                                          
1514                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1515                     try {                                                                                
1516                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1517                         // wait no longer than 1sec at a time                                            
1518                         this.wait(1000);                                                                 
1519                     } catch (InterruptedException ex) {                                                  
1520                         // Ignore                                                                        
1521                     }                                                                                    
1522                 }                                                                                        
1523                 if (DEBUG_LOADERS) {                                                                     
1524                     Log.d(TAG, "waited "                                                                 
1525                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1526                             + "ms for previous step to finish binding");                                 
1527                 }                                                                                        
1528             }                                                                                            
1529         }                                                                                                
1530                                                                                                          
1531         void runBindSynchronousPage(int synchronousBindPage) {                                           
1532             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1533                 // Ensure that we have a valid page index to load synchronously                          
1534                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1535                         "valid page index");                                                             
1536             }                                                                                            
1537             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1538                 // Ensure that we don't try and bind a specified page when the pages have not been       
1539                 // loaded already (we should load everything asynchronously in that case)                
1540                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1541             }                                                                                            
1542             synchronized (mLock) {                                                                       
1543                 if (mIsLoaderTaskRunning) {                                                              
1544                     // Ensure that we are never running the background loading at this point since       
1545                     // we also touch the background collections                                          
1546                     throw new RuntimeException("Error! Background loading is already running");          
1547                 }                                                                                        
1548             }                                                                                            
1549                                                                                                          
1550             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1551             //      data structures, we can't allow any other thread to touch that data, but because     
1552             //      this call is synchronous, we can get away with not locking).                         
1553                                                                                                          
1554             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1555             // operations from the previous activity.  We need to ensure that all queued operations      
1556             // are executed before any synchronous binding work is done.                                 
1557             mHandler.flush();                                                                            
1558                                                                                                          
1559             // Divide the set of loaded items into those that we are binding synchronously, and          
1560             // everything else that is to be bound normally (asynchronously).                            
1561             bindWorkspace(synchronousBindPage);                                                          
1562             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1563             //      arise from that.                                                                     
1564             onlyBindAllApps();                                                                           
1565         }                                                                                                
1566                                                                                                          
1567         public void run() {                                                                              
1568             synchronized (mLock) {                                                                       
1569                 if (mStopped) {                                                                          
1570                     return;                                                                              
1571                 }                                                                                        
1572                 mIsLoaderTaskRunning = true;                                                             
1573             }                                                                                            
1574             // Optimize for end-user experience: if the Launcher is up and // running with the           
1575             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1576             // workspace first (default).                                                                
1577             keep_running: {                                                                              
1578                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1579                 loadAndBindWorkspace();                                                                  
1580                                                                                                          
1581                 if (mStopped) {                                                                          
1582                     break keep_running;                                                                  
1583                 }                                                                                        
1584                                                                                                          
1585                 waitForIdle();                                                                           
1586                                                                                                          
1587                 // second step                                                                           
1588                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1589                 loadAndBindAllApps();                                                                    
1590             }                                                                                            
1591                                                                                                          
1592             // Clear out this reference, otherwise we end up holding it until all of the                 
1593             // callback runnables are done.                                                              
1594             mContext = null;                                                                             
1595                                                                                                          
1596             synchronized (mLock) {                                                                       
1597                 // If we are still the last one to be scheduled, remove ourselves.                       
1598                 if (mLoaderTask == this) {                                                               
1599                     mLoaderTask = null;                                                                  
1600                 }                                                                                        
1601                 mIsLoaderTaskRunning = false;                                                            
1602                 mHasLoaderCompletedOnce = true;                                                          
1603             }                                                                                            
1604         }                                                                                                
1605                                                                                                          
1606         public void stopLocked() {                                                                       
1607             synchronized (LoaderTask.this) {                                                             
1608                 mStopped = true;                                                                         
1609                 this.notify();                                                                           
1610             }                                                                                            
1611         }                                                                                                
1612                                                                                                          
1613         /**                                                                                              
1614          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1615          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1616          * object that was around when the deferred message was scheduled, and if there's                
1617          * a new Callbacks object around then also return null.  This will save us from                  
1618          * calling onto it with data that will be ignored.                                               
1619          */                                                                                              
1620         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1621             synchronized (mLock) {                                                                       
1622                 if (mStopped) {                                                                          
1623                     return null;                                                                         
1624                 }                                                                                        
1625                                                                                                          
1626                 if (mCallbacks == null) {                                                                
1627                     return null;                                                                         
1628                 }                                                                                        
1629                                                                                                          
1630                 final Callbacks callbacks = mCallbacks.get();                                            
1631                 if (callbacks != oldCallbacks) {                                                         
1632                     return null;                                                                         
1633                 }                                                                                        
1634                 if (callbacks == null) {                                                                 
1635                     Log.w(TAG, "no mCallbacks");                                                         
1636                     return null;                                                                         
1637                 }                                                                                        
1638                                                                                                          
1639                 return callbacks;                                                                        
1640             }                                                                                            
1641         }                                                                                                
1642                                                                                                          
1643         // check & update map of what's occupied; used to discard overlapping/invalid items              
1644         private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {         
1645             LauncherAppState app = LauncherAppState.getInstance();                                       
1646             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1647             final int countX = (int) profile.numColumns;                                                 
1648             final int countY = (int) profile.numRows;                                                    
1649                                                                                                          
1650             long containerIndex = item.screenId;                                                         
1651             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1652                 // Return early if we detect that an item is under the hotseat button                    
1653                 if (mCallbacks == null ||                                                                
1654                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1655                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1656                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1657                             + item.cellY + ") occupied by all apps");                                    
1658                     return false;                                                                        
1659                 }                                                                                        
1660                                                                                                          
1661                 final ItemInfo[][] hotseatItems =                                                        
1662                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1663                                                                                                          
1664                 if (item.screenId >= profile.numHotseatIcons) {                                          
1665                     Log.e(TAG, "Error loading shortcut " + item                                          
1666                             + " into hotseat position " + item.screenId                                  
1667                             + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1)         
1668                             + ")");                                                                      
1669                     return false;                                                                        
1670                 }                                                                                        
1671                                                                                                          
1672                 if (hotseatItems != null) {                                                              
1673                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1674                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1675                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1676                                 + item.cellY + ") occupied by "                                          
1677                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1678                                 [(int) item.screenId][0]);                                               
1679                             return false;                                                                
1680                     } else {                                                                             
1681                         hotseatItems[(int) item.screenId][0] = item;                                     
1682                         return true;                                                                     
1683                     }                                                                                    
1684                 } else {                                                                                 
1685                     final ItemInfo[][] items = new ItemInfo[(int) profile.numHotseatIcons][1];           
1686                     items[(int) item.screenId][0] = item;                                                
1687                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1688                     return true;                                                                         
1689                 }                                                                                        
1690             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1691                 // Skip further checking if it is not the hotseat or workspace container                 
1692                 return true;                                                                             
1693             }                                                                                            
1694                                                                                                          
1695             if (!occupied.containsKey(item.screenId)) {                                                  
1696                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1697                 occupied.put(item.screenId, items);                                                      
1698             }                                                                                            
1699                                                                                                          
1700             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1701             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1702                     item.cellX < 0 || item.cellY < 0 ||                                                  
1703                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1704                 Log.e(TAG, "Error loading shortcut " + item                                              
1705                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1706                         + item.cellX + "," + item.cellY                                                  
1707                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1708                 return false;                                                                            
1709             }                                                                                            
1710                                                                                                          
1711             // Check if any workspace icons overlap with each other                                      
1712             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1713                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1714                     if (screens[x][y] != null) {                                                         
1715                         Log.e(TAG, "Error loading shortcut " + item                                      
1716                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1717                             + x + "," + y                                                                
1718                             + ") occupied by "                                                           
1719                             + screens[x][y]);                                                            
1720                         return false;                                                                    
1721                     }                                                                                    
1722                 }                                                                                        
1723             }                                                                                            
1724             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1725                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1726                     screens[x][y] = item;                                                                
1727                 }                                                                                        
1728             }                                                                                            
1729                                                                                                          
1730             return true;                                                                                 
1731         }                                                                                                
1732                                                                                                          
1733         /** Clears all the sBg data structures */                                                        
1734         private void clearSBgDataStructures() {                                                          
1735             synchronized (sBgLock) {                                                                     
1736                 sBgWorkspaceItems.clear();                                                               
1737                 sBgAppWidgets.clear();                                                                   
1738                 sBgFolders.clear();                                                                      
1739                 sBgItemsIdMap.clear();                                                                   
1740                 sBgWorkspaceScreens.clear();                                                             
1741             }                                                                                            
1742         }                                                                                                
1743                                                                                                          
1744         private void loadWorkspace() {                                                                   
1745             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
1746                                                                                                          
1747             final Context context = mContext;                                                            
1748             final ContentResolver contentResolver = context.getContentResolver();                        
1749             final PackageManager manager = context.getPackageManager();                                  
1750             final boolean isSafeMode = manager.isSafeMode();                                             
1751             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1752             final boolean isSdCardReady = context.registerReceiver(null,                                 
1753                     new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                             
1754                                                                                                          
1755             LauncherAppState app = LauncherAppState.getInstance();                                       
1756             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1757             int countX = (int) profile.numColumns;                                                       
1758             int countY = (int) profile.numRows;                                                          
1759                                                                                                          
1760             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1761                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1762                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1763             }                                                                                            
1764                                                                                                          
1765             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1766                 // append the user's Launcher2 shortcuts                                                 
1767                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1768                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1769             } else {                                                                                     
1770                 // Make sure the default workspace is loaded                                             
1771                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1772                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1773             }                                                                                            
1774                                                                                                          
1775             synchronized (sBgLock) {                                                                     
1776                 clearSBgDataStructures();                                                                
1777                 final HashMap<String, Integer> installingPkgs = PackageInstallerCompat                   
1778                         .getInstance(mContext).updateAndGetActiveSessionCache();                         
1779                                                                                                          
1780                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1781                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1782                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
1783                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
1784                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1785                                                                                                          
1786                 // +1 for the hotseat (it can be larger than the workspace)                              
1787                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1788                 // before any earlier duplicates)                                                        
1789                 final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();                        
1790                                                                                                          
1791                 try {                                                                                    
1792                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1793                     final int intentIndex = c.getColumnIndexOrThrow                                      
1794                             (LauncherSettings.Favorites.INTENT);                                         
1795                     final int titleIndex = c.getColumnIndexOrThrow                                       
1796                             (LauncherSettings.Favorites.TITLE);                                          
1797                     final int containerIndex = c.getColumnIndexOrThrow(                                  
1798                             LauncherSettings.Favorites.CONTAINER);                                       
1799                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
1800                             LauncherSettings.Favorites.ITEM_TYPE);                                       
1801                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
1802                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
1803                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
1804                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
1805                     final int screenIndex = c.getColumnIndexOrThrow(                                     
1806                             LauncherSettings.Favorites.SCREEN);                                          
1807                     final int cellXIndex = c.getColumnIndexOrThrow                                       
1808                             (LauncherSettings.Favorites.CELLX);                                          
1809                     final int cellYIndex = c.getColumnIndexOrThrow                                       
1810                             (LauncherSettings.Favorites.CELLY);                                          
1811                     final int spanXIndex = c.getColumnIndexOrThrow                                       
1812                             (LauncherSettings.Favorites.SPANX);                                          
1813                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
1814                             LauncherSettings.Favorites.SPANY);                                           
1815                     final int rankIndex = c.getColumnIndexOrThrow(                                       
1816                             LauncherSettings.Favorites.RANK);                                            
1817                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
1818                             LauncherSettings.Favorites.RESTORED);                                        
1819                     final int profileIdIndex = c.getColumnIndexOrThrow(                                  
1820                             LauncherSettings.Favorites.PROFILE_ID);                                      
1821                     final int optionsIndex = c.getColumnIndexOrThrow(                                    
1822                             LauncherSettings.Favorites.OPTIONS);                                         
1823                     final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);                         
1824                                                                                                          
1825                     final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();          
1826                     for (UserHandleCompat user : mUserManager.getUserProfiles()) {                       
1827                         allUsers.put(mUserManager.getSerialNumberForUser(user), user);                   
1828                     }                                                                                    
1829                                                                                                          
1830                     ShortcutInfo info;                                                                   
1831                     String intentDescription;                                                            
1832                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1833                     int container;                                                                       
1834                     long id;                                                                             
1835                     long serialNumber;                                                                   
1836                     Intent intent;                                                                       
1837                     UserHandleCompat user;                                                               
1838                                                                                                          
1839                     while (!mStopped && c.moveToNext()) {                                                
1840                         try {                                                                            
1841                             int itemType = c.getInt(itemTypeIndex);                                      
1842                             boolean restored = 0 != c.getInt(restoredIndex);                             
1843                             boolean allowMissingTarget = false;                                          
1844                             container = c.getInt(containerIndex);                                        
1845                                                                                                          
1846                             switch (itemType) {                                                          
1847                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1848                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1849                                 id = c.getLong(idIndex);                                                 
1850                                 intentDescription = c.getString(intentIndex);                            
1851                                 serialNumber = c.getInt(profileIdIndex);                                 
1852                                 user = allUsers.get(serialNumber);                                       
1853                                 int promiseType = c.getInt(restoredIndex);                               
1854                                 int disabledState = 0;                                                   
1855                                 boolean itemReplaced = false;                                            
1856                                 if (user == null) {                                                      
1857                                     // User has been deleted remove the item.                            
1858                                     itemsToRemove.add(id);                                               
1859                                     continue;                                                            
1860                                 }                                                                        
1861                                 try {                                                                    
1862                                     intent = Intent.parseUri(intentDescription, 0);                      
1863                                     ComponentName cn = intent.getComponent();                            
1864                                     if (cn != null && cn.getPackageName() != null) {                     
1865                                         boolean validPkg = launcherApps.isPackageEnabledForProfile(      
1866                                                 cn.getPackageName(), user);                              
1867                                         boolean validComponent = validPkg &&                             
1868                                                 launcherApps.isActivityEnabledForProfile(cn, user);      
1869                                                                                                          
1870                                         if (validComponent) {                                            
1871                                             if (restored) {                                              
1872                                                 // no special handling necessary for this item           
1873                                                 restoredRows.add(id);                                    
1874                                                 restored = false;                                        
1875                                             }                                                            
1876                                         } else if (validPkg) {                                           
1877                                             intent = null;                                               
1878                                             if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
1879                                                 // We allow auto install apps to have their intent       
1880                                                 // updated after an install.                             
1881                                                 intent = manager.getLaunchIntentForPackage(              
1882                                                         cn.getPackageName());                            
1883                                                 if (intent != null) {                                    
1884                                                     ContentValues values = new ContentValues();          
1885                                                     values.put(LauncherSettings.Favorites.INTENT,        
1886                                                             intent.toUri(0));                            
1887                                                     updateItem(id, values);                              
1888                                                 }                                                        
1889                                             }                                                            
1890                                                                                                          
1891                                             if (intent == null) {                                        
1892                                                 // The app is installed but the component is no          
1893                                                 // longer available.                                     
1894                                                 Launcher.addDumpLog(TAG,                                 
1895                                                         "Invalid component removed: " + cn, true);       
1896                                                 itemsToRemove.add(id);                                   
1897                                                 continue;                                                
1898                                             } else {                                                     
1899                                                 // no special handling necessary for this item           
1900                                                 restoredRows.add(id);                                    
1901                                                 restored = false;                                        
1902                                             }                                                            
1903                                         } else if (restored) {                                           
1904                                             // Package is not yet available but might be                 
1905                                             // installed later.                                          
1906                                             Launcher.addDumpLog(TAG,                                     
1907                                                     "package not yet restored: " + cn, true);            
1908                                                                                                          
1909                                             if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
1910                                                 // Restore has started once.                             
1911                                             } else if (installingPkgs.containsKey(cn.getPackageName())) {
1912                                                 // App restore has started. Update the flag              
1913                                                 promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;        
1914                                                 ContentValues values = new ContentValues();              
1915                                                 values.put(LauncherSettings.Favorites.RESTORED,          
1916                                                         promiseType);                                    
1917                                                 updateItem(id, values);                                  
1918                                             } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE🔵
1919                                                 // This is a common app. Try to replace this.            
1920                                                 int appType = CommonAppTypeParser.decodeItemTypeFromFlag(🔵
1921                                                 CommonAppTypeParser parser = new CommonAppTypeParser(id, 🔵
1922                                                 if (parser.findDefaultApp()) {                           
1923                                                     // Default app found. Replace it.                    
1924                                                     intent = parser.parsedIntent;                        
1925                                                     cn = intent.getComponent();                          
1926                                                     ContentValues values = parser.parsedValues;          
1927                                                     values.put(LauncherSettings.Favorites.RESTORED, 0);  
1928                                                     updateItem(id, values);                              
1929                                                     restored = false;                                    
1930                                                     itemReplaced = true;                                 
1931                                                                                                          
1932                                             } else if (REMOVE_UNRESTORED_ICONS) {                        
1933                                                 Launcher.addDumpLog(TAG,                                 
1934                                                         "Unrestored package removed: " + cn, true);      
1935                                                 itemsToRemove.add(id);                                   
1936                                                 continue;                                                
1937                                             }                                                            
1938                                             } else if (REMOVE_UNRESTORED_ICONS) {                        
1939                                                 Launcher.addDumpLog(TAG,                                 
1940                                                         "Unrestored package removed: " + cn, true);      
1941                                                 itemsToRemove.add(id);                                   
1942                                                 continue;                                                
1943                                             }                                                            
1944                                         } else if (launcherApps.isAppEnabled(                            
1945                                                 manager, cn.getPackageName(),                            
1946                                                 PackageManager.GET_UNINSTALLED_PACKAGES)) {              
1947                                             // Package is present but not available.                     
1948                                             allowMissingTarget = true;                                   
1949                                             disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;    
1950                                         } else if (!isSdCardReady) {                                     
1951                                             // SdCard is not ready yet. Package might get available,     
1952                                             // once it is ready.                                         
1953                                             Launcher.addDumpLog(TAG, "Invalid package: " + cn            
1954                                                     + " (check again later)", true);                     
1955                                             HashSet<String> pkgs = sPendingPackages.get(user);           
1956                                             if (pkgs == null) {                                          
1957                                                 pkgs = new HashSet<String>();                            
1958                                                 sPendingPackages.put(user, pkgs);                        
1959                                             }                                                            
1960                                             pkgs.add(cn.getPackageName());                               
1961                                             allowMissingTarget = true;                                   
1962                                             // Add the icon on the workspace anyway.                     
1963                                                                                                          
1964                                         } else {                                                         
1965                                             // Do not wait for external media load anymore.              
1966                                             // Log the invalid package, and remove it                    
1967                                             Launcher.addDumpLog(TAG,                                     
1968                                                     "Invalid package removed: " + cn, true);             
1969                                             itemsToRemove.add(id);                                       
1970                                             continue;                                                    
1971                                         }                                                                
1972                                     } else if (cn == null) {                                             
1973                                         // For shortcuts with no component, keep them as they are        
1974                                         restoredRows.add(id);                                            
1975                                         restored = false;                                                
1976                                     }                                                                    
1977                                 } catch (URISyntaxException e) {                                         
1978                                     Launcher.addDumpLog(TAG,                                             
1979                                             "Invalid uri: " + intentDescription, true);                  
1980                                     continue;                                                            
1981                                 }                                                                        
1982                                                                                                          
1983                                 boolean useLowResIcon = container >= 0 &&                                
1984                                         c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;          
1985                                                                                                          
1986                                 if (itemReplaced) {                                                      
1987                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
1988                                         info = getAppShortcutInfo(manager, intent, user, context, null,  
1989                                                 cursorIconInfo.iconIndex, titleIndex,                    
1990                                                 false, useLowResIcon);                                   
1991                                     } else {                                                             
1992                                         // Don't replace items for other profiles.                       
1993                                         itemsToRemove.add(id);                                           
1994                                         continue;                                                        
1995                                     }                                                                    
1996                                 } else if (restored) {                                                   
1997                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
1998                                         Launcher.addDumpLog(TAG,                                         
1999                                                 "constructing info for partially restored package",      
2000                                                 true);                                                   
2001                                         info = getRestoredItemInfo(c, titleIndex, intent,                
2002                                                 promiseType, itemType, cursorIconInfo, context);         
2003                                         intent = getRestoredItemIntent(c, context, intent);              
2004                                     } else {                                                             
2005                                         // Don't restore items for other profiles.                       
2006                                         itemsToRemove.add(id);                                           
2007                                         continue;                                                        
2008                                     }                                                                    
2009                                 } else if (itemType ==                                                   
2010                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
2011                                     info = getAppShortcutInfo(manager, intent, user, context, c,         
2012                                             cursorIconInfo.iconIndex, titleIndex,                        
2013                                             allowMissingTarget, useLowResIcon);                          
2014                                 } else {                                                                 
2015                                     info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);      
2016                                                                                                          
2017                                     // App shortcuts that used to be automatically added to Launcher     
2018                                     // didn't always have the correct intent flags set, so do that       
2019                                     // here                                                              
2020                                     if (intent.getAction() != null &&                                    
2021                                         intent.getCategories() != null &&                                
2022                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
2023                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
2024                                         intent.addFlags(                                                 
2025                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
2026                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2027                                     }                                                                    
2028                                 }                                                                        
2029                                                                                                          
2030                                 if (info != null) {                                                      
2031                                     info.id = id;                                                        
2032                                     info.intent = intent;                                                
2033                                     info.container = container;                                          
2034                                     info.screenId = c.getInt(screenIndex);                               
2035                                     info.cellX = c.getInt(cellXIndex);                                   
2036                                     info.cellY = c.getInt(cellYIndex);                                   
2037                                     info.rank = c.getInt(rankIndex);                                     
2038                                     info.spanX = 1;                                                      
2039                                     info.spanY = 1;                                                      
2040                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);          
2041                                     if (info.promisedIntent != null) {                                   
2042                                         info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber🔵
2043                                     }                                                                    
2044                                     info.isDisabled = disabledState;                                     
2045                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {         
2046                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;          
2047                                     }                                                                    
2048                                                                                                          
2049                                     // check & update map of what's occupied                             
2050                                     if (!checkItemPlacement(occupied, info)) {                           
2051                                         itemsToRemove.add(id);                                           
2052                                         break;                                                           
2053                                     }                                                                    
2054                                                                                                          
2055                                     if (restored) {                                                      
2056                                         ComponentName cn = info.getTargetComponent();                    
2057                                         if (cn != null) {                                                
2058                                             Integer progress = installingPkgs.get(cn.getPackageName());  
2059                                             if (progress != null) {                                      
2060                                                 info.setInstallProgress(progress);                       
2061                                             } else {                                                     
2062                                                 info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
2063                                             }                                                            
2064                                         }                                                                
2065                                     }                                                                    
2066                                                                                                          
2067                                     switch (container) {                                                 
2068                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2069                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2070                                         sBgWorkspaceItems.add(info);                                     
2071                                         break;                                                           
2072                                     default:                                                             
2073                                         // Item is in a user folder                                      
2074                                         FolderInfo folderInfo =                                          
2075                                                 findOrMakeFolder(sBgFolders, container);                 
2076                                         folderInfo.add(info);                                            
2077                                         break;                                                           
2078                                     }                                                                    
2079                                     sBgItemsIdMap.put(info.id, info);                                    
2080                                 } else {                                                                 
2081                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2082                                 }                                                                        
2083                                 break;                                                                   
2084                                                                                                          
2085                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2086                                 id = c.getLong(idIndex);                                                 
2087                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2088                                                                                                          
2089                                 // Do not trim the folder label, as is was set by the user.              
2090                                 folderInfo.title = c.getString(titleIndex);                              
2091                                 folderInfo.id = id;                                                      
2092                                 folderInfo.container = container;                                        
2093                                 folderInfo.screenId = c.getInt(screenIndex);                             
2094                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2095                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2096                                 folderInfo.spanX = 1;                                                    
2097                                 folderInfo.spanY = 1;                                                    
2098                                 folderInfo.options = c.getInt(optionsIndex);                             
2099                                                                                                          
2100                                 // check & update map of what's occupied                                 
2101                                 if (!checkItemPlacement(occupied, folderInfo)) {                         
2102                                     itemsToRemove.add(id);                                               
2103                                     break;                                                               
2104                                 }                                                                        
2105                                                                                                          
2106                                 switch (container) {                                                     
2107                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2108                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2109                                         sBgWorkspaceItems.add(folderInfo);                               
2110                                         break;                                                           
2111                                 }                                                                        
2112                                                                                                          
2113                                 if (restored) {                                                          
2114                                     // no special handling required for restored folders                 
2115                                     restoredRows.add(id);                                                
2116                                 }                                                                        
2117                                                                                                          
2118                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2119                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2120                                 break;                                                                   
2121                                                                                                          
2122                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2123                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
2124                                 // Read all Launcher-specific widget details                             
2125                                 boolean customWidget = itemType ==                                       
2126                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
2127                                                                                                          
2128                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2129                                 serialNumber= c.getLong(profileIdIndex);                                 
2130                                 user = mUserManager.getUserForSerialNumber(serialNumber);                
2131                                 if (user == null) {                                                      
2132                                     // User has been deleted remove the item.                            
2133                                     itemsToRemove.add(id);                                               
2134                                     continue;                                                            
2135                                 }                                                                        
2136                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2137                                 id = c.getLong(idIndex);                                                 
2138                                 user = allUsers.get(serialNumber);                                       
2139                                 if (user == null) {                                                      
2140                                     itemsToRemove.add(id);                                               
2141                                     continue;                                                            
2142                                 }                                                                        
2143                                                                                                          
2144                                 final ComponentName component =                                          
2145                                         ComponentName.unflattenFromString(savedProvider);                
2146                                                                                                          
2147                                 final int restoreStatus = c.getInt(restoredIndex);                       
2148                                 final boolean isIdValid = (restoreStatus &                               
2149                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                   
2150                                 final boolean wasProviderReady = (restoreStatus &                        
2151                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;             
2152                                                                                                          
2153                                 final LauncherAppWidgetProviderInfo provider =                           
2154                                         LauncherModel.getProviderInfo(context,                           
2155                                                 ComponentName.unflattenFromString(savedProvider),        
2156                                                 user);                                                   
2157                                                                                                          
2158                                 final boolean isProviderReady = isValidProvider(provider);               
2159                                 if (!isSafeMode && !customWidget &&                                      
2160                                         wasProviderReady && !isProviderReady) {                          
2161                                     String log = "Deleting widget that isn't installed anymore: "        
2162                                             + "id=" + id + " appWidgetId=" + appWidgetId;                
2163                                                                                                          
2164                                     Log.e(TAG, log);                                                     
2165                                     Launcher.addDumpLog(TAG, log, false);                                
2166                                     itemsToRemove.add(id);                                               
2167                                 } else {                                                                 
2168                                     if (isProviderReady) {                                               
2169                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2170                                                 provider.provider);                                      
2171                                                                                                          
2172                                         int status = restoreStatus;                                      
2173                                         if (!wasProviderReady) {                                         
2174                                             // If provider was not previously ready, update the          
2175                                             // status and UI flag.                                       
2176                                                                                                          
2177                                             // Id would be valid only if the widget restore broadcast was🔵
2178                                             if (isIdValid) {                                             
2179                                                 status = LauncherAppWidgetInfo.RESTORE_COMPLETED;        
2180                                             } else {                                                     
2181                                                 status &= ~LauncherAppWidgetInfo                         
2182                                                         .FLAG_PROVIDER_NOT_READY;                        
2183                                             }                                                            
2184                                         }                                                                
2185                                         appWidgetInfo.restoreStatus = status;                            
2186                                     } else {                                                             
2187                                         Log.v(TAG, "Widget restore pending id=" + id                     
2188                                                 + " appWidgetId=" + appWidgetId                          
2189                                                 + " status =" + restoreStatus);                          
2190                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2191                                                 component);                                              
2192                                         appWidgetInfo.restoreStatus = restoreStatus;                     
2193                                         Integer installProgress = installingPkgs.get(component.getPackage🔵
2194                                                                                                          
2195                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) 🔵
2196                                             // Restore has started once.                                 
2197                                         } else if (installProgress != null) {                            
2198                                             // App restore has started. Update the flag                  
2199                                             appWidgetInfo.restoreStatus |=                               
2200                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;          
2201                                         } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {             
2202                                             Launcher.addDumpLog(TAG,                                     
2203                                                     "Unrestored widget removed: " + component, true);    
2204                                             itemsToRemove.add(id);                                       
2205                                             continue;                                                    
2206                                         }                                                                
2207                                                                                                          
2208                                         appWidgetInfo.installProgress =                                  
2209                                                 installProgress == null ? 0 : installProgress;           
2210                                     }                                                                    
2211                                                                                                          
2212                                     appWidgetInfo.id = id;                                               
2213                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2214                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2215                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2216                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2217                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2218                                     appWidgetInfo.user = user;                                           
2219                                                                                                          
2220                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2221                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2222                                         Log.e(TAG, "Widget found where container != " +                  
2223                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2224                                         continue;                                                        
2225                                     }                                                                    
2226                                                                                                          
2227                                     appWidgetInfo.container = container;                                 
2228                                     // check & update map of what's occupied                             
2229                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {                  
2230                                         itemsToRemove.add(id);                                           
2231                                         break;                                                           
2232                                     }                                                                    
2233                                                                                                          
2234                                     if (!customWidget) {                                                 
2235                                         String providerName =                                            
2236                                                 appWidgetInfo.providerName.flattenToString();            
2237                                         if (!providerName.equals(savedProvider) ||                       
2238                                                 (appWidgetInfo.restoreStatus != restoreStatus)) {        
2239                                             ContentValues values = new ContentValues();                  
2240                                             values.put(                                                  
2241                                                     LauncherSettings.Favorites.APPWIDGET_PROVIDER,       
2242                                                     providerName);                                       
2243                                             values.put(LauncherSettings.Favorites.RESTORED,              
2244                                                     appWidgetInfo.restoreStatus);                        
2245                                             updateItem(id, values);                                      
2246                                         }                                                                
2247                                     }                                                                    
2248                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2249                                     sBgAppWidgets.add(appWidgetInfo);                                    
2250                                 }                                                                        
2251                                 break;                                                                   
2252                             }                                                                            
2253                         } catch (Exception e) {                                                          
2254                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2255                         }                                                                                
2256                     }                                                                                    
2257                 } finally {                                                                              
2258                     if (c != null) {                                                                     
2259                         c.close();                                                                       
2260                     }                                                                                    
2261                 }                                                                                        
2262                                                                                                          
2263                 // Break early if we've stopped loading                                                  
2264                 if (mStopped) {                                                                          
2265                     clearSBgDataStructures();                                                            
2266                     return;                                                                              
2267                 }                                                                                        
2268                                                                                                          
2269                 if (itemsToRemove.size() > 0) {                                                          
2270                     // Remove dead items                                                                 
2271                     contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI,                       
2272                             Utilities.createDbSelectionQuery(                                            
2273                                     LauncherSettings.Favorites._ID, itemsToRemove), null);               
2274                         if (DEBUG_LOADERS) {                                                             
2275                         Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(                      
2276                                 LauncherSettings.Favorites._ID, itemsToRemove));                         
2277                         }                                                                                
2278                                                                                                          
2279                     // Remove any empty folder                                                           
2280                     for (long folderId : LauncherAppState.getLauncherProvider()                          
2281                             .deleteEmptyFolders()) {                                                     
2282                         sBgWorkspaceItems.remove(sBgFolders.get(folderId));                              
2283                         sBgFolders.remove(folderId);                                                     
2284                         sBgItemsIdMap.remove(folderId);                                                  
2285                     }                                                                                    
2286                 }                                                                                        
2287                                                                                                          
2288                 if (restoredRows.size() > 0) {                                                           
2289                     // Update restored items that no longer require special handling                     
2290                         ContentValues values = new ContentValues();                                      
2291                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2292                     contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values,               
2293                             Utilities.createDbSelectionQuery(                                            
2294                                     LauncherSettings.Favorites._ID, restoredRows), null);                
2295                 }                                                                                        
2296                                                                                                          
2297                 if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                     
2298                     context.registerReceiver(new AppsAvailabilityCheck(),                                
2299                             new IntentFilter(StartupReceiver.SYSTEM_READY),                              
2300                             null, sWorker);                                                              
2301                 }                                                                                        
2302                                                                                                          
2303                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2304                                                                                                          
2305                     // Remove any empty screens                                                          
2306                     ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);            
2307                 for (ItemInfo item: sBgItemsIdMap) {                                                     
2308                         long screenId = item.screenId;                                                   
2309                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&            
2310                                 unusedScreens.contains(screenId)) {                                      
2311                             unusedScreens.remove(screenId);                                              
2312                         }                                                                                
2313                     }                                                                                    
2314                                                                                                          
2315                     // If there are any empty screens remove them, and update.                           
2316                     if (unusedScreens.size() != 0) {                                                     
2317                         sBgWorkspaceScreens.removeAll(unusedScreens);                                    
2318                         updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                        
2319                     }                                                                                    
2320                                                                                                          
2321                 if (DEBUG_LOADERS) {                                                                     
2322                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2323                     Log.d(TAG, "workspace layout: ");                                                    
2324                     int nScreens = occupied.size();                                                      
2325                     for (int y = 0; y < countY; y++) {                                                   
2326                         String line = "";                                                                
2327                                                                                                          
2328                         for (int i = 0; i < nScreens; i++) {                                             
2329                             long screenId = occupied.keyAt(i);                                           
2330                             if (screenId > 0) {                                                          
2331                                 line += " | ";                                                           
2332                             }                                                                            
2333                             ItemInfo[][] screen = occupied.valueAt(i);                                   
2334                             for (int x = 0; x < countX; x++) {                                           
2335                                 if (x < screen.length && y < screen[x].length) {                         
2336                                     line += (screen[x][y] != null) ? "#" : ".";                          
2337                                 } else {                                                                 
2338                                     line += "!";                                                         
2339                                 }                                                                        
2340                             }                                                                            
2341                         }                                                                                
2342                         Log.d(TAG, "[ " + line + " ]");                                                  
2343                     }                                                                                    
2344                 }                                                                                        
2345             }                                                                                            
2346         }                                                                                                
2347                                                                                                          
2348         /**                                                                                              
2349          * Partially updates the item without any notification. Must be called on the worker thread.     
2350          */                                                                                              
2351         private void updateItem(long itemId, ContentValues update) {                                     
2352             mContext.getContentResolver().update(                                                        
2353                     LauncherSettings.Favorites.CONTENT_URI,                                              
2354                     update,                                                                              
2355                     BaseColumns._ID + "= ?",                                                             
2356                     new String[]{Long.toString(itemId)});                                                
2357         }                                                                                                
2358                                                                                                          
2359         /** Filters the set of items who are directly or indirectly (via another container) on the       
2360          * specified screen. */                                                                          
2361         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2362                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2363                 ArrayList<ItemInfo> currentScreenItems,                                                  
2364                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2365             // Purge any null ItemInfos                                                                  
2366             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2367             while (iter.hasNext()) {                                                                     
2368                 ItemInfo i = iter.next();                                                                
2369                 if (i == null) {                                                                         
2370                     iter.remove();                                                                       
2371                 }                                                                                        
2372             }                                                                                            
2373                                                                                                          
2374             // Order the set of items by their containers first, this allows use to walk through the     
2375             // list sequentially, build up a list of containers that are in the specified screen,        
2376             // as well as all items in those containers.                                                 
2377             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2378             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2379                 @Override                                                                                
2380                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2381                     return (int) (lhs.container - rhs.container);                                        
2382                 }                                                                                        
2383             });                                                                                          
2384             for (ItemInfo info : allWorkspaceItems) {                                                    
2385                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2386                     if (info.screenId == currentScreenId) {                                              
2387                         currentScreenItems.add(info);                                                    
2388                         itemsOnScreen.add(info.id);                                                      
2389                     } else {                                                                             
2390                         otherScreenItems.add(info);                                                      
2391                     }                                                                                    
2392                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2393                     currentScreenItems.add(info);                                                        
2394                     itemsOnScreen.add(info.id);                                                          
2395                 } else {                                                                                 
2396                     if (itemsOnScreen.contains(info.container)) {                                        
2397                         currentScreenItems.add(info);                                                    
2398                         itemsOnScreen.add(info.id);                                                      
2399                     } else {                                                                             
2400                         otherScreenItems.add(info);                                                      
2401                     }                                                                                    
2402                 }                                                                                        
2403             }                                                                                            
2404         }                                                                                                
2405                                                                                                          
2406         /** Filters the set of widgets which are on the specified screen. */                             
2407         private void filterCurrentAppWidgets(long currentScreenId,                                       
2408                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2409                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2410                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2411                                                                                                          
2412             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2413                 if (widget == null) continue;                                                            
2414                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2415                         widget.screenId == currentScreenId) {                                            
2416                     currentScreenWidgets.add(widget);                                                    
2417                 } else {                                                                                 
2418                     otherScreenWidgets.add(widget);                                                      
2419                 }                                                                                        
2420             }                                                                                            
2421         }                                                                                                
2422                                                                                                          
2423         /** Filters the set of folders which are on the specified screen. */                             
2424         private void filterCurrentFolders(long currentScreenId,                                          
2425                 LongArrayMap<ItemInfo> itemsIdMap,                                                       
2426                 LongArrayMap<FolderInfo> folders,                                                        
2427                 LongArrayMap<FolderInfo> currentScreenFolders,                                           
2428                 LongArrayMap<FolderInfo> otherScreenFolders) {                                           
2429                                                                                                          
2430             int total = folders.size();                                                                  
2431             for (int i = 0; i < total; i++) {                                                            
2432                 long id = folders.keyAt(i);                                                              
2433                 FolderInfo folder = folders.valueAt(i);                                                  
2434                                                                                                          
2435                 ItemInfo info = itemsIdMap.get(id);                                                      
2436                 if (info == null || folder == null) continue;                                            
2437                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2438                         info.screenId == currentScreenId) {                                              
2439                     currentScreenFolders.put(id, folder);                                                
2440                 } else {                                                                                 
2441                     otherScreenFolders.put(id, folder);                                                  
2442                 }                                                                                        
2443             }                                                                                            
2444         }                                                                                                
2445                                                                                                          
2446         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2447          * right) */                                                                                     
2448         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2449             final LauncherAppState app = LauncherAppState.getInstance();                                 
2450             final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                      
2451             // XXX: review this                                                                          
2452             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2453                 @Override                                                                                
2454                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2455                     int cellCountX = (int) profile.numColumns;                                           
2456                     int cellCountY = (int) profile.numRows;                                              
2457                     int screenOffset = cellCountX * cellCountY;                                          
2458                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2459                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2460                             lhs.cellY * cellCountX + lhs.cellX);                                         
2461                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2462                             rhs.cellY * cellCountX + rhs.cellX);                                         
2463                     return (int) (lr - rr);                                                              
2464                 }                                                                                        
2465             });                                                                                          
2466         }                                                                                                
2467                                                                                                          
2468         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2469                 final ArrayList<Long> orderedScreens) {                                                  
2470             final Runnable r = new Runnable() {                                                          
2471                 @Override                                                                                
2472                 public void run() {                                                                      
2473                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2474                     if (callbacks != null) {                                                             
2475                         callbacks.bindScreens(orderedScreens);                                           
2476                     }                                                                                    
2477                 }                                                                                        
2478             };                                                                                           
2479             runOnMainThread(r);                                                                          
2480         }                                                                                                
2481                                                                                                          
2482         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2483                 final ArrayList<ItemInfo> workspaceItems,                                                
2484                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2485                 final LongArrayMap<FolderInfo> folders,                                                  
2486                 ArrayList<Runnable> deferredBindRunnables) {                                             
2487                                                                                                          
2488             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2489                                                                                                          
2490             // Bind the workspace items                                                                  
2491             int N = workspaceItems.size();                                                               
2492             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2493                 final int start = i;                                                                     
2494                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2495                 final Runnable r = new Runnable() {                                                      
2496                     @Override                                                                            
2497                     public void run() {                                                                  
2498                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2499                         if (callbacks != null) {                                                         
2500                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2501                                     false);                                                              
2502                         }                                                                                
2503                     }                                                                                    
2504                 };                                                                                       
2505                 if (postOnMainThread) {                                                                  
2506                     synchronized (deferredBindRunnables) {                                               
2507                         deferredBindRunnables.add(r);                                                    
2508                     }                                                                                    
2509                 } else {                                                                                 
2510                     runOnMainThread(r);                                                                  
2511                 }                                                                                        
2512             }                                                                                            
2513                                                                                                          
2514             // Bind the folders                                                                          
2515             if (!folders.isEmpty()) {                                                                    
2516                 final Runnable r = new Runnable() {                                                      
2517                     public void run() {                                                                  
2518                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2519                         if (callbacks != null) {                                                         
2520                             callbacks.bindFolders(folders);                                              
2521                         }                                                                                
2522                     }                                                                                    
2523                 };                                                                                       
2524                 if (postOnMainThread) {                                                                  
2525                     synchronized (deferredBindRunnables) {                                               
2526                         deferredBindRunnables.add(r);                                                    
2527                     }                                                                                    
2528                 } else {                                                                                 
2529                     runOnMainThread(r);                                                                  
2530                 }                                                                                        
2531             }                                                                                            
2532                                                                                                          
2533             // Bind the widgets, one at a time                                                           
2534             N = appWidgets.size();                                                                       
2535             for (int i = 0; i < N; i++) {                                                                
2536                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2537                 final Runnable r = new Runnable() {                                                      
2538                     public void run() {                                                                  
2539                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2540                         if (callbacks != null) {                                                         
2541                             callbacks.bindAppWidget(widget);                                             
2542                         }                                                                                
2543                     }                                                                                    
2544                 };                                                                                       
2545                 if (postOnMainThread) {                                                                  
2546                     deferredBindRunnables.add(r);                                                        
2547                 } else {                                                                                 
2548                     runOnMainThread(r);                                                                  
2549                 }                                                                                        
2550             }                                                                                            
2551         }                                                                                                
2552                                                                                                          
2553         /**                                                                                              
2554          * Binds all loaded data to actual views on the main thread.                                     
2555          */                                                                                              
2556         private void bindWorkspace(int synchronizeBindPage) {                                            
2557             final long t = SystemClock.uptimeMillis();                                                   
2558             Runnable r;                                                                                  
2559                                                                                                          
2560             // Don't use these two variables in any of the callback runnables.                           
2561             // Otherwise we hold a reference to them.                                                    
2562             final Callbacks oldCallbacks = mCallbacks.get();                                             
2563             if (oldCallbacks == null) {                                                                  
2564                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2565                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2566                 return;                                                                                  
2567             }                                                                                            
2568                                                                                                          
2569             // Save a copy of all the bg-thread collections                                              
2570             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2571             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2572                     new ArrayList<LauncherAppWidgetInfo>();                                              
2573             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2574                                                                                                          
2575             final LongArrayMap<FolderInfo> folders;                                                      
2576             final LongArrayMap<ItemInfo> itemsIdMap;                                                     
2577                                                                                                          
2578             synchronized (sBgLock) {                                                                     
2579                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2580                 appWidgets.addAll(sBgAppWidgets);                                                        
2581                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2582                                                                                                          
2583                 folders = sBgFolders.clone();                                                            
2584                 itemsIdMap = sBgItemsIdMap.clone();                                                      
2585             }                                                                                            
2586                                                                                                          
2587             final boolean isLoadingSynchronously =                                                       
2588                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2589             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2590                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2591             if (currScreen >= orderedScreenIds.size()) {                                                 
2592                 // There may be no workspace screens (just hotseat items and an empty page).             
2593                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2594             }                                                                                            
2595             final int currentScreen = currScreen;                                                        
2596             final long currentScreenId = currentScreen < 0                                               
2597                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2598                                                                                                          
2599             // Load all the items that are on the current page first (and in the process, unbind         
2600             // all the existing workspace items before we call startBinding() below.                     
2601             unbindWorkspaceItemsOnMainThread();                                                          
2602                                                                                                          
2603             // Separate the items that are on the current screen, and all the other remaining items      
2604             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2605             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2606             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2607                     new ArrayList<LauncherAppWidgetInfo>();                                              
2608             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2609                     new ArrayList<LauncherAppWidgetInfo>();                                              
2610             LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();                              
2611             LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();                                
2612                                                                                                          
2613             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2614                     otherWorkspaceItems);                                                                
2615             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2616                     otherAppWidgets);                                                                    
2617             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2618                     otherFolders);                                                                       
2619             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2620             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2621                                                                                                          
2622             // Tell the workspace that we're about to start binding items                                
2623             r = new Runnable() {                                                                         
2624                 public void run() {                                                                      
2625                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2626                     if (callbacks != null) {                                                             
2627                         callbacks.startBinding();                                                        
2628                     }                                                                                    
2629                 }                                                                                        
2630             };                                                                                           
2631             runOnMainThread(r);                                                                          
2632                                                                                                          
2633             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2634                                                                                                          
2635             // Load items on the current page                                                            
2636             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2637                     currentFolders, null);                                                               
2638             if (isLoadingSynchronously) {                                                                
2639                 r = new Runnable() {                                                                     
2640                     public void run() {                                                                  
2641                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2642                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2643                             callbacks.onPageBoundSynchronously(currentScreen);                           
2644                         }                                                                                
2645                     }                                                                                    
2646                 };                                                                                       
2647                 runOnMainThread(r);                                                                      
2648             }                                                                                            
2649                                                                                                          
2650             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2651             // work until after the first render)                                                        
2652             synchronized (mDeferredBindRunnables) {                                                      
2653                 mDeferredBindRunnables.clear();                                                          
2654             }                                                                                            
2655             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2656                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2657                                                                                                          
2658             // Tell the workspace that we're done binding items                                          
2659             r = new Runnable() {                                                                         
2660                 public void run() {                                                                      
2661                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2662                     if (callbacks != null) {                                                             
2663                         callbacks.finishBindingItems();                                                  
2664                     }                                                                                    
2665                                                                                                          
2666                     // If we're profiling, ensure this is the last thing in the queue.                   
2667                     if (DEBUG_LOADERS) {                                                                 
2668                         Log.d(TAG, "bound workspace in "                                                 
2669                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2670                     }                                                                                    
2671                                                                                                          
2672                     mIsLoadingAndBindingWorkspace = false;                                               
2673                 }                                                                                        
2674             };                                                                                           
2675             if (isLoadingSynchronously) {                                                                
2676                 synchronized (mDeferredBindRunnables) {                                                  
2677                     mDeferredBindRunnables.add(r);                                                       
2678                 }                                                                                        
2679             } else {                                                                                     
2680                 runOnMainThread(r);                                                                      
2681             }                                                                                            
2682         }                                                                                                
2683                                                                                                          
2684         private void loadAndBindAllApps() {                                                              
2685             if (DEBUG_LOADERS) {                                                                         
2686                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2687             }                                                                                            
2688             if (!mAllAppsLoaded) {                                                                       
2689                 loadAllApps();                                                                           
2690                 synchronized (LoaderTask.this) {                                                         
2691                     if (mStopped) {                                                                      
2692                         return;                                                                          
2693                     }                                                                                    
2694                 }                                                                                        
2695                 updateIconCache();                                                                       
2696                 synchronized (LoaderTask.this) {                                                         
2697                     if (mStopped) {                                                                      
2698                         return;                                                                          
2699                     }                                                                                    
2700                     mAllAppsLoaded = true;                                                               
2701                 }                                                                                        
2702             } else {                                                                                     
2703                 onlyBindAllApps();                                                                       
2704             }                                                                                            
2705         }                                                                                                
2706                                                                                                          
2707         private void updateIconCache() {                                                                 
2708             // Ignore packages which have a promise icon.                                                
2709             HashSet<String> packagesToIgnore = new HashSet<>();                                          
2710             synchronized (sBgLock) {                                                                     
2711                 for (ItemInfo info : sBgItemsIdMap) {                                                    
2712                     if (info instanceof ShortcutInfo) {                                                  
2713                         ShortcutInfo si = (ShortcutInfo) info;                                           
2714                         if (si.isPromise() && si.getTargetComponent() != null) {                         
2715                             packagesToIgnore.add(si.getTargetComponent().getPackageName());              
2716                         }                                                                                
2717                     } else if (info instanceof LauncherAppWidgetInfo) {                                  
2718                         LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;                       
2719                         if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {        
2720                             packagesToIgnore.add(lawi.providerName.getPackageName());                    
2721                         }                                                                                
2722                     }                                                                                    
2723                 }                                                                                        
2724             }                                                                                            
2725             mIconCache.updateDbIcons(packagesToIgnore);                                                  
2726         }                                                                                                
2727                                                                                                          
2728         private void onlyBindAllApps() {                                                                 
2729             final Callbacks oldCallbacks = mCallbacks.get();                                             
2730             if (oldCallbacks == null) {                                                                  
2731                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2732                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2733                 return;                                                                                  
2734             }                                                                                            
2735                                                                                                          
2736             // shallow copy                                                                              
2737             @SuppressWarnings("unchecked")                                                               
2738             final ArrayList<AppInfo> list                                                                
2739                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2740             final WidgetsModel widgetList = mBgWidgetsModel.clone();                                     
2741             Runnable r = new Runnable() {                                                                
2742                 public void run() {                                                                      
2743                     final long t = SystemClock.uptimeMillis();                                           
2744                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2745                     if (callbacks != null) {                                                             
2746                         callbacks.bindAllApplications(list);                                             
2747                         callbacks.bindAllPackages(widgetList);                                           
2748                     }                                                                                    
2749                     if (DEBUG_LOADERS) {                                                                 
2750                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2751                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2752                     }                                                                                    
2753                 }                                                                                        
2754             };                                                                                           
2755             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2756             if (isRunningOnMainThread) {                                                                 
2757                 r.run();                                                                                 
2758             } else {                                                                                     
2759                 mHandler.post(r);                                                                        
2760             }                                                                                            
2761         }                                                                                                
2762                                                                                                          
2763         private void loadAllApps() {                                                                     
2764             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2765                                                                                                          
2766             final Callbacks oldCallbacks = mCallbacks.get();                                             
2767             if (oldCallbacks == null) {                                                                  
2768                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2769                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2770                 return;                                                                                  
2771             }                                                                                            
2772                                                                                                          
2773             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2774                                                                                                          
2775             // Clear the list of apps                                                                    
2776             mBgAllAppsList.clear();                                                                      
2777             for (UserHandleCompat user : profiles) {                                                     
2778                 // Query for the set of apps                                                             
2779                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                     
2780                 final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); 
2781                 if (DEBUG_LOADERS) {                                                                     
2782                     Log.d(TAG, "getActivityList took "                                                   
2783                             + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);             
2784                     Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);         
2785                 }                                                                                        
2786                 // Fail if we don't have any apps                                                        
2787                 // TODO: Fix this. Only fail for the current user.                                       
2788                 if (apps == null || apps.isEmpty()) {                                                    
2789                     return;                                                                              
2790                 }                                                                                        
2791                                                                                                          
2792                 // Create the ApplicationInfos                                                           
2793                 for (int i = 0; i < apps.size(); i++) {                                                  
2794                     LauncherActivityInfoCompat app = apps.get(i);                                        
2795                     // This builds the icon bitmaps.                                                     
2796                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2797                 }                                                                                        
2798                                                                                                          
2799                 final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);   
2800                 if (heuristic != null) {                                                                 
2801                     runAfterBindCompletes(new Runnable() {                                               
2802                                                                                                          
2803                         @Override                                                                        
2804                         public void run() {                                                              
2805                             heuristic.processUserApps(apps);                                             
2806                         }                                                                                
2807                     });                                                                                  
2808                 }                                                                                        
2809             }                                                                                            
2810             // Huh? Shouldn't this be inside the Runnable below?                                         
2811             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2812             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2813                                                                                                          
2814             // Post callback on main thread                                                              
2815             mHandler.post(new Runnable() {                                                               
2816                 public void run() {                                                                      
2817                                                                                                          
2818                     final long bindTime = SystemClock.uptimeMillis();                                    
2819                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2820                     if (callbacks != null) {                                                             
2821                         callbacks.bindAllApplications(added);                                            
2822                         if (DEBUG_LOADERS) {                                                             
2823                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2824                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2825                         }                                                                                
2826                     } else {                                                                             
2827                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2828                     }                                                                                    
2829                 }                                                                                        
2830             });                                                                                          
2831             // Cleanup any data stored for a deleted user.                                               
2832             ManagedProfileHeuristic.processAllUsers(profiles, mContext);                                 
2833                                                                                                          
2834             loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks),             
2835                     true /* refresh */);                                                                 
2836             if (DEBUG_LOADERS) {                                                                         
2837                 Log.d(TAG, "Icons processed in "                                                         
2838                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2839             }                                                                                            
2840         }                                                                                                
2841                                                                                                          
2842         public void dumpState() {                                                                        
2843             synchronized (sBgLock) {                                                                     
2844                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2845                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2846                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2847                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2848             }                                                                                            
2849         }                                                                                                
2850     }                                                                                                    
2851                                                                                                          
2852     /**                                                                                                  
2853      * Called when the icons for packages have been updated in the icon cache.                           
2854      */                                                                                                  
2855     public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {          
2856         final Callbacks callbacks = getCallback();                                                       
2857         final ArrayList<AppInfo> updatedApps = new ArrayList<>();                                        
2858         final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();                              
2859                                                                                                          
2860         // If any package icon has changed (app was updated while launcher was dead),                    
2861         // update the corresponding shortcuts.                                                           
2862         synchronized (sBgLock) {                                                                         
2863             for (ItemInfo info : sBgItemsIdMap) {                                                        
2864                 if (info instanceof ShortcutInfo && user.equals(info.user)                               
2865                         && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {          
2866                     ShortcutInfo si = (ShortcutInfo) info;                                               
2867                     ComponentName cn = si.getTargetComponent();                                          
2868                     if (cn != null && updatedPackages.contains(cn.getPackageName())) {                   
2869                         si.updateIcon(mIconCache);                                                       
2870                         updatedShortcuts.add(si);                                                        
2871                     }                                                                                    
2872                 }                                                                                        
2873             }                                                                                            
2874             mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);                     
2875         }                                                                                                
2876                                                                                                          
2877         if (!updatedShortcuts.isEmpty()) {                                                               
2878             final UserHandleCompat userFinal = user;                                                     
2879             mHandler.post(new Runnable() {                                                               
2880                                                                                                          
2881                 public void run() {                                                                      
2882                     Callbacks cb = getCallback();                                                        
2883                     if (cb != null && callbacks == cb) {                                                 
2884                         cb.bindShortcutsChanged(updatedShortcuts,                                        
2885                                 new ArrayList<ShortcutInfo>(), userFinal);                               
2886                     }                                                                                    
2887                 }                                                                                        
2888             });                                                                                          
2889         }                                                                                                
2890                                                                                                          
2891         if (!updatedApps.isEmpty()) {                                                                    
2892             mHandler.post(new Runnable() {                                                               
2893                                                                                                          
2894                 public void run() {                                                                      
2895                     Callbacks cb = getCallback();                                                        
2896                     if (cb != null && callbacks == cb) {                                                 
2897                         cb.bindAppsUpdated(updatedApps);                                                 
2898                     }                                                                                    
2899                 }                                                                                        
2900             });                                                                                          
2901         }                                                                                                
2902                                                                                                          
2903         // Reload widget list. No need to refresh, as we only want to update the icons and labels.       
2904         loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);                             
2905     }                                                                                                    
2906                                                                                                          
2907     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2908         sWorker.post(task);                                                                              
2909     }                                                                                                    
2910                                                                                                          
2911     @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {                                       
2912                                                                                                          
2913         @Override                                                                                        
2914         public void onReceive(Context context, Intent intent) {                                          
2915             synchronized (sBgLock) {                                                                     
2916                 final LauncherAppsCompat launcherApps = LauncherAppsCompat                               
2917                         .getInstance(mApp.getContext());                                                 
2918                 final PackageManager manager = context.getPackageManager();                              
2919                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
2920                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
2921                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
2922                     UserHandleCompat user = entry.getKey();                                              
2923                     packagesRemoved.clear();                                                             
2924                     packagesUnavailable.clear();                                                         
2925                     for (String pkg : entry.getValue()) {                                                
2926                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
2927                             boolean packageOnSdcard = launcherApps.isAppEnabled(                         
2928                                     manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);              
2929                             if (packageOnSdcard) {                                                       
2930                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
2931                                 packagesUnavailable.add(pkg);                                            
2932                             } else {                                                                     
2933                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
2934                                 packagesRemoved.add(pkg);                                                
2935                             }                                                                            
2936                         }                                                                                
2937                     }                                                                                    
2938                     if (!packagesRemoved.isEmpty()) {                                                    
2939                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,       
2940                                 packagesRemoved.toArray(new String[packagesRemoved.size()]), user));     
2941                     }                                                                                    
2942                     if (!packagesUnavailable.isEmpty()) {                                                
2943                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,  
2944                                 packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user🔵
2945                     }                                                                                    
2946                 }                                                                                        
2947                 sPendingPackages.clear();                                                                
2948             }                                                                                            
2949         }                                                                                                
2950     }                                                                                                    
2951                                                                                                          
2952     private class PackageUpdatedTask implements Runnable {                                               
2953         int mOp;                                                                                         
2954         String[] mPackages;                                                                              
2955         UserHandleCompat mUser;                                                                          
2956                                                                                                          
2957         public static final int OP_NONE = 0;                                                             
2958         public static final int OP_ADD = 1;                                                              
2959         public static final int OP_UPDATE = 2;                                                           
2960         public static final int OP_REMOVE = 3; // uninstlled                                             
2961         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2962                                                                                                          
2963                                                                                                          
2964         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
2965             mOp = op;                                                                                    
2966             mPackages = packages;                                                                        
2967             mUser = user;                                                                                
2968         }                                                                                                
2969                                                                                                          
2970         public void run() {                                                                              
2971             if (!mHasLoaderCompletedOnce) {                                                              
2972                 // Loader has not yet run.                                                               
2973                 return;                                                                                  
2974             }                                                                                            
2975             final Context context = mApp.getContext();                                                   
2976                                                                                                          
2977             final String[] packages = mPackages;                                                         
2978             final int N = packages.length;                                                               
2979             switch (mOp) {                                                                               
2980                 case OP_ADD: {                                                                           
2981                     for (int i=0; i<N; i++) {                                                            
2982                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
2983                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2984                         mBgAllAppsList.addPackage(context, packages[i], mUser);                          
2985                     }                                                                                    
2986                                                                                                          
2987                     ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);     
2988                     if (heuristic != null) {                                                             
2989                         heuristic.processPackageAdd(mPackages);                                          
2990                     }                                                                                    
2991                     break;                                                                               
2992                 }                                                                                        
2993                 case OP_UPDATE:                                                                          
2994                     for (int i=0; i<N; i++) {                                                            
2995                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
2996                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2997                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
2998                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
2999                     }                                                                                    
3000                     break;                                                                               
3001                 case OP_REMOVE: {                                                                        
3002                     ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);     
3003                     if (heuristic != null) {                                                             
3004                         heuristic.processPackageRemoved(mPackages);                                      
3005                     }                                                                                    
3006                     for (int i=0; i<N; i++) {                                                            
3007                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3008                         mIconCache.removeIconsForPkg(packages[i], mUser);                                
3009                     }                                                                                    
3010                     // Fall through                                                                      
3011                 }                                                                                        
3012                 case OP_UNAVAILABLE:                                                                     
3013                     for (int i=0; i<N; i++) {                                                            
3014                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3015                         mBgAllAppsList.removePackage(packages[i], mUser);                                
3016                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
3017                     }                                                                                    
3018                     break;                                                                               
3019             }                                                                                            
3020                                                                                                          
3021             ArrayList<AppInfo> added = null;                                                             
3022             ArrayList<AppInfo> modified = null;                                                          
3023             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
3024                                                                                                          
3025             if (mBgAllAppsList.added.size() > 0) {                                                       
3026                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
3027                 mBgAllAppsList.added.clear();                                                            
3028             }                                                                                            
3029             if (mBgAllAppsList.modified.size() > 0) {                                                    
3030                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
3031                 mBgAllAppsList.modified.clear();                                                         
3032             }                                                                                            
3033             if (mBgAllAppsList.removed.size() > 0) {                                                     
3034                 removedApps.addAll(mBgAllAppsList.removed);                                              
3035                 mBgAllAppsList.removed.clear();                                                          
3036             }                                                                                            
3037                                                                                                          
3038             final Callbacks callbacks = getCallback();                                                   
3039             if (callbacks == null) {                                                                     
3040                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
3041                 return;                                                                                  
3042             }                                                                                            
3043                                                                                                          
3044             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                   
3045                     new HashMap<ComponentName, AppInfo>();                                               
3046                                                                                                          
3047             if (added != null) {                                                                         
3048                     addAppsToAllApps(context, added);                                                    
3049                 for (AppInfo ai : added) {                                                               
3050                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3051                 }                                                                                        
3052             }                                                                                            
3053                                                                                                          
3054             if (modified != null) {                                                                      
3055                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
3056                 for (AppInfo ai : modified) {                                                            
3057                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3058                 }                                                                                        
3059                                                                                                          
3060                 mHandler.post(new Runnable() {                                                           
3061                     public void run() {                                                                  
3062                         Callbacks cb = getCallback();                                                    
3063                         if (callbacks == cb && cb != null) {                                             
3064                             callbacks.bindAppsUpdated(modifiedFinal);                                    
3065                         }                                                                                
3066                     }                                                                                    
3067                 });                                                                                      
3068             }                                                                                            
3069                                                                                                          
3070             // Update shortcut infos                                                                     
3071             if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                     
3072                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
3073                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
3074                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
3075                                                                                                          
3076                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
3077                 synchronized (sBgLock) {                                                                 
3078                     for (ItemInfo info : sBgItemsIdMap) {                                                
3079                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                   
3080                             ShortcutInfo si = (ShortcutInfo) info;                                       
3081                             boolean infoUpdated = false;                                                 
3082                             boolean shortcutUpdated = false;                                             
3083                                                                                                          
3084                             // Update shortcuts which use iconResource.                                  
3085                             if ((si.iconResource != null)                                                
3086                                     && packageSet.contains(si.iconResource.packageName)) {               
3087                                 Bitmap icon = Utilities.createIconBitmap(                                
3088                                         si.iconResource.packageName,                                     
3089                                         si.iconResource.resourceName, context);                          
3090                                 if (icon != null) {                                                      
3091                                     si.setIcon(icon);                                                    
3092                                     si.usingFallbackIcon = false;                                        
3093                                     infoUpdated = true;                                                  
3094                                 }                                                                        
3095                             }                                                                            
3096                                                                                                          
3097                             ComponentName cn = si.getTargetComponent();                                  
3098                             if (cn != null && packageSet.contains(cn.getPackageName())) {                
3099                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
3100                                                                                                          
3101                                 if (si.isPromise()) {                                                    
3102                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
3103                                         // Auto install icon                                             
3104                                         PackageManager pm = context.getPackageManager();                 
3105                                         ResolveInfo matched = pm.resolveActivity(                        
3106                                                 new Intent(Intent.ACTION_MAIN)                           
3107                                                 .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), 
3108                                                 PackageManager.MATCH_DEFAULT_ONLY);                      
3109                                         if (matched == null) {                                           
3110                                             // Try to find the best match activity.                      
3111                                             Intent intent = pm.getLaunchIntentForPackage(                
3112                                                     cn.getPackageName());                                
3113                                             if (intent != null) {                                        
3114                                                 cn = intent.getComponent();                              
3115                                                 appInfo = addedOrUpdatedApps.get(cn);                    
3116                                             }                                                            
3117                                                                                                          
3118                                             if ((intent == null) || (appInfo == null)) {                 
3119                                                 removedShortcuts.add(si);                                
3120                                                 continue;                                                
3121                                             }                                                            
3122                                             si.promisedIntent = intent;                                  
3123                                         }                                                                
3124                                     }                                                                    
3125                                                                                                          
3126                                     // Restore the shortcut.                                             
3127                                     if (appInfo != null) {                                               
3128                                         si.flags = appInfo.flags;                                        
3129                                     }                                                                    
3130                                                                                                          
3131                                     si.intent = si.promisedIntent;                                       
3132                                     si.promisedIntent = null;                                            
3133                                     si.status = ShortcutInfo.DEFAULT;                                    
3134                                     infoUpdated = true;                                                  
3135                                     si.updateIcon(mIconCache);                                           
3136                                 }                                                                        
3137                                                                                                          
3138                                 if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())  
3139                                         && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATIO🔵
3140                                     si.updateIcon(mIconCache);                                           
3141                                     si.title = Utilities.trim(appInfo.title);                            
3142                                     si.contentDescription = appInfo.contentDescription;                  
3143                                     infoUpdated = true;                                                  
3144                                 }                                                                        
3145                                                                                                          
3146                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
3147                                     // Since package was just updated, the target must be available now. 
3148                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
3149                                     shortcutUpdated = true;                                              
3150                                 }                                                                        
3151                             }                                                                            
3152                                                                                                          
3153                             if (infoUpdated || shortcutUpdated) {                                        
3154                                 updatedShortcuts.add(si);                                                
3155                             }                                                                            
3156                             if (infoUpdated) {                                                           
3157                                 updateItemInDatabase(context, si);                                       
3158                             }                                                                            
3159                         } else if (info instanceof LauncherAppWidgetInfo) {                              
3160                             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;             
3161                             if (mUser.equals(widgetInfo.user)                                            
3162                                     && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_🔵
3163                                     && packageSet.contains(widgetInfo.providerName.getPackageName())) {  
3164                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
3165                                 widgets.add(widgetInfo);                                                 
3166                                 updateItemInDatabase(context, widgetInfo);                               
3167                             }                                                                            
3168                         }                                                                                
3169                     }                                                                                    
3170                 }                                                                                        
3171                                                                                                          
3172                 if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                        
3173                     mHandler.post(new Runnable() {                                                       
3174                                                                                                          
3175                         public void run() {                                                              
3176                             Callbacks cb = getCallback();                                                
3177                             if (callbacks == cb && cb != null) {                                         
3178                                 callbacks.bindShortcutsChanged(                                          
3179                                         updatedShortcuts, removedShortcuts, mUser);                      
3180                             }                                                                            
3181                         }                                                                                
3182                     });                                                                                  
3183                     if (!removedShortcuts.isEmpty()) {                                                   
3184                         deleteItemsFromDatabase(context, removedShortcuts);                              
3185                     }                                                                                    
3186                 }                                                                                        
3187                 if (!widgets.isEmpty()) {                                                                
3188                     mHandler.post(new Runnable() {                                                       
3189                         public void run() {                                                              
3190                             Callbacks cb = getCallback();                                                
3191                             if (callbacks == cb && cb != null) {                                         
3192                                 callbacks.bindWidgetsRestored(widgets);                                  
3193                             }                                                                            
3194                         }                                                                                
3195                     });                                                                                  
3196                 }                                                                                        
3197             }                                                                                            
3198                                                                                                          
3199             final ArrayList<String> removedPackageNames =                                                
3200                     new ArrayList<String>();                                                             
3201             if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                             
3202                 // Mark all packages in the broadcast to be removed                                      
3203                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3204             } else if (mOp == OP_UPDATE) {                                                               
3205                 // Mark disabled packages in the broadcast to be removed                                 
3206                 for (int i=0; i<N; i++) {                                                                
3207                     if (isPackageDisabled(context, packages[i], mUser)) {                                
3208                         removedPackageNames.add(packages[i]);                                            
3209                     }                                                                                    
3210                 }                                                                                        
3211             }                                                                                            
3212                                                                                                          
3213             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
3214                 final int removeReason;                                                                  
3215                 if (mOp == OP_UNAVAILABLE) {                                                             
3216                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
3217                 } else {                                                                                 
3218                     // Remove all the components associated with this package                            
3219                     for (String pn : removedPackageNames) {                                              
3220                         deletePackageFromDatabase(context, pn, mUser);                                   
3221                     }                                                                                    
3222                     // Remove all the specific components                                                
3223                     for (AppInfo a : removedApps) {                                                      
3224                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
3225                         deleteItemsFromDatabase(context, infos);                                         
3226                     }                                                                                    
3227                     removeReason = 0;                                                                    
3228                 }                                                                                        
3229                                                                                                          
3230                 // Remove any queued items from the install queue                                        
3231                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
3232                 // Call the components-removed callback                                                  
3233                 mHandler.post(new Runnable() {                                                           
3234                     public void run() {                                                                  
3235                         Callbacks cb = getCallback();                                                    
3236                         if (callbacks == cb && cb != null) {                                             
3237                             callbacks.bindComponentsRemoved(                                             
3238                                     removedPackageNames, removedApps, mUser, removeReason);              
3239                         }                                                                                
3240                     }                                                                                    
3241                 });                                                                                      
3242             }                                                                                            
3243                                                                                                          
3244             // onProvidersChanged method (API >= 17) already refreshed the widget list                   
3245             loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17);              
3246                                                                                                          
3247             // Write all the logs to disk                                                                
3248             mHandler.post(new Runnable() {                                                               
3249                 public void run() {                                                                      
3250                     Callbacks cb = getCallback();                                                        
3251                     if (callbacks == cb && cb != null) {                                                 
3252                         callbacks.dumpLogsToLocalData();                                                 
3253                     }                                                                                    
3254                 }                                                                                        
3255             });                                                                                          
3256         }                                                                                                
3257     }                                                                                                    
3258                                                                                                          
3259     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,                
3260             boolean refresh) {                                                                           
3261         ArrayList<LauncherAppWidgetProviderInfo> results =                                               
3262                 new ArrayList<LauncherAppWidgetProviderInfo>();                                          
3263         try {                                                                                            
3264             synchronized (sBgLock) {                                                                     
3265                 if (sBgWidgetProviders == null || refresh) {                                             
3266                     HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders              
3267                             = new HashMap<>();                                                           
3268                     AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);             
3269                     LauncherAppWidgetProviderInfo info;                                                  
3270                                                                                                          
3271                     List<AppWidgetProviderInfo> widgets = wm.getAllProviders();                          
3272                     for (AppWidgetProviderInfo pInfo : widgets) {                                        
3273                         info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);           
3274                         UserHandleCompat user = wm.getUser(info);                                        
3275                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
3276                     }                                                                                    
3277                                                                                                          
3278                     Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values(); 
3279                     for (CustomAppWidget widget : customWidgets) {                                       
3280                         info = new LauncherAppWidgetProviderInfo(context, widget);                       
3281                         UserHandleCompat user = wm.getUser(info);                                        
3282                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
3283                     }                                                                                    
3284                     // Replace the global list at the very end, so that if there is an exception,        
3285                     // previously loaded provider list is used.                                          
3286                     sBgWidgetProviders = tmpWidgetProviders;                                             
3287                 }                                                                                        
3288                 results.addAll(sBgWidgetProviders.values());                                             
3289                 return results;                                                                          
3290             }                                                                                            
3291         } catch (Exception e) {                                                                          
3292             if (e.getCause() instanceof TransactionTooLargeException) {                                  
3293                 // the returned value may be incomplete and will not be refreshed until the next         
3294                 // time Launcher starts.                                                                 
3295                 // TODO: after figuring out a repro step, introduce a dirty bit to check when            
3296                 // onResume is called to refresh the widget provider list.                               
3297                 synchronized (sBgLock) {                                                                 
3298                     if (sBgWidgetProviders != null) {                                                    
3299                         results.addAll(sBgWidgetProviders.values());                                     
3300                     }                                                                                    
3301                     return results;                                                                      
3302                 }                                                                                        
3303             } else {                                                                                     
3304                 throw e;                                                                                 
3305             }                                                                                            
3306         }                                                                                                
3307     }                                                                                                    
3308                                                                                                          
3309     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,         
3310             UserHandleCompat user) {                                                                     
3311         synchronized (sBgLock) {                                                                         
3312             if (sBgWidgetProviders == null) {                                                            
3313                 getWidgetProviders(ctx, false /* refresh */);                                            
3314             }                                                                                            
3315             return sBgWidgetProviders.get(new ComponentKey(name, user));                                 
3316         }                                                                                                
3317     }                                                                                                    
3318                                                                                                          
3319     public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks,         
3320             final boolean refresh) {                                                                     
3321                                                                                                          
3322         runOnWorkerThread(new Runnable() {                                                               
3323             @Override                                                                                    
3324             public void run() {                                                                          
3325                 updateWidgetsModel(context, refresh);                                                    
3326                 final WidgetsModel model = mBgWidgetsModel.clone();                                      
3327                                                                                                          
3328                 mHandler.post(new Runnable() {                                                           
3329                     @Override                                                                            
3330                     public void run() {                                                                  
3331                         Callbacks cb = getCallback();                                                    
3332                         if (callbacks == cb && cb != null) {                                             
3333                             callbacks.bindAllPackages(model);                                            
3334                         }                                                                                
3335                     }                                                                                    
3336                 });                                                                                      
3337                 // update the Widget entries inside DB on the worker thread.                             
3338                 LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(                  
3339                         model.getRawList());                                                             
3340             }                                                                                            
3341         });                                                                                              
3342     }                                                                                                    
3343                                                                                                          
3344     /**                                                                                                  
3345      * Returns a list of ResolveInfos/AppWidgetInfos.                                                    
3346      *                                                                                                   
3347      * @see #loadAndBindWidgetsAndShortcuts                                                              
3348      */                                                                                                  
3349     @Thunk void updateWidgetsModel(Context context, boolean refresh) {                                   
3350         PackageManager packageManager = context.getPackageManager();                                     
3351         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3352         widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));                                
3353         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3354         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3355         mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);                                     
3356     }                                                                                                    
3357                                                                                                          
3358     @Thunk static boolean isPackageDisabled(Context context, String packageName,                         
3359             UserHandleCompat user) {                                                                     
3360         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3361         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3362     }                                                                                                    
3363                                                                                                          
3364     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3365             UserHandleCompat user) {                                                                     
3366         if (cn == null) {                                                                                
3367             return false;                                                                                
3368         }                                                                                                
3369         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3370         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3371             return false;                                                                                
3372         }                                                                                                
3373         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3374     }                                                                                                    
3375                                                                                                          
3376     public static boolean isValidPackage(Context context, String packageName,                            
3377             UserHandleCompat user) {                                                                     
3378         if (packageName == null) {                                                                       
3379             return false;                                                                                
3380         }                                                                                                
3381         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3382         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3383     }                                                                                                    
3384                                                                                                          
3385     /**                                                                                                  
3386      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3387      * to a package that is not yet installed on the system.                                             
3388      */                                                                                                  
3389     public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent,                     
3390             int promiseType, int itemType, CursorIconInfo iconInfo, Context context) {                   
3391         final ShortcutInfo info = new ShortcutInfo();                                                    
3392         info.user = UserHandleCompat.myUserHandle();                                                     
3393                                                                                                          
3394         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3395         // the fallback icon                                                                             
3396         if (icon == null) {                                                                              
3397             mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);              
3398         } else {                                                                                         
3399             info.setIcon(icon);                                                                          
3400         }                                                                                                
3401                                                                                                          
3402         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3403             String title = (c != null) ? c.getString(titleIndex) : null;                                 
3404             if (!TextUtils.isEmpty(title)) {                                                             
3405                 info.title = Utilities.trim(title);                                                      
3406             }                                                                                            
3407         } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                            
3408             if (TextUtils.isEmpty(info.title)) {                                                         
3409                 info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";                 
3410             }                                                                                            
3411         } else {                                                                                         
3412             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3413         }                                                                                                
3414                                                                                                          
3415         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3416         info.itemType = itemType;                                                                        
3417         info.promisedIntent = intent;                                                                    
3418         info.status = promiseType;                                                                       
3419         return info;                                                                                     
3420     }                                                                                                    
3421                                                                                                          
3422     /**                                                                                                  
3423      * Make an Intent object for a restored application or shortcut item that points                     
3424      * to the market page for the item.                                                                  
3425      */                                                                                                  
3426     @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                      
3427         ComponentName componentName = intent.getComponent();                                             
3428         return getMarketIntent(componentName.getPackageName());                                          
3429     }                                                                                                    
3430                                                                                                          
3431     static Intent getMarketIntent(String packageName) {                                                  
3432         return new Intent(Intent.ACTION_VIEW)                                                            
3433             .setData(new Uri.Builder()                                                                   
3434                 .scheme("market")                                                                        
3435                 .authority("details")                                                                    
3436                 .appendQueryParameter("id", packageName)                                                 
3437                 .build());                                                                               
3438     }                                                                                                    
3439                                                                                                          
3440     /**                                                                                                  
3441      * Make an ShortcutInfo object for a shortcut that is an application.                                
3442      *                                                                                                   
3443      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3444      */                                                                                                  
3445     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                        
3446             UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,             
3447             boolean allowMissingTarget, boolean useLowResIcon) {                                         
3448         if (user == null) {                                                                              
3449             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3450             return null;                                                                                 
3451         }                                                                                                
3452                                                                                                          
3453         ComponentName componentName = intent.getComponent();                                             
3454         if (componentName == null) {                                                                     
3455             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3456             return null;                                                                                 
3457         }                                                                                                
3458                                                                                                          
3459         Intent newIntent = new Intent(intent.getAction(), null);                                         
3460         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3461         newIntent.setComponent(componentName);                                                           
3462         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3463         if ((lai == null) && !allowMissingTarget) {                                                      
3464             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3465             return null;                                                                                 
3466         }                                                                                                
3467                                                                                                          
3468         final ShortcutInfo info = new ShortcutInfo();                                                    
3469         mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);                
3470         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                     
3471             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3472             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3473         }                                                                                                
3474                                                                                                          
3475         // from the db                                                                                   
3476         if (TextUtils.isEmpty(info.title) && c != null) {                                                
3477             info.title =  Utilities.trim(c.getString(titleIndex));                                       
3478         }                                                                                                
3479                                                                                                          
3480         // fall back to the class name of the activity                                                   
3481         if (info.title == null) {                                                                        
3482             info.title = componentName.getClassName();                                                   
3483         }                                                                                                
3484                                                                                                          
3485         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3486         info.user = user;                                                                                
3487         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3488         if (lai != null) {                                                                               
3489             info.flags = AppInfo.initFlags(lai);                                                         
3490         }                                                                                                
3491         return info;                                                                                     
3492     }                                                                                                    
3493                                                                                                          
3494     static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,                                 
3495             ItemInfoFilter f) {                                                                          
3496         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3497         for (ItemInfo i : infos) {                                                                       
3498             if (i instanceof ShortcutInfo) {                                                             
3499                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3500                 ComponentName cn = info.getTargetComponent();                                            
3501                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3502                     filtered.add(info);                                                                  
3503                 }                                                                                        
3504             } else if (i instanceof FolderInfo) {                                                        
3505                 FolderInfo info = (FolderInfo) i;                                                        
3506                 for (ShortcutInfo s : info.contents) {                                                   
3507                     ComponentName cn = s.getTargetComponent();                                           
3508                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3509                         filtered.add(s);                                                                 
3510                     }                                                                                    
3511                 }                                                                                        
3512             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3513                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3514                 ComponentName cn = info.providerName;                                                    
3515                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3516                     filtered.add(info);                                                                  
3517                 }                                                                                        
3518             }                                                                                            
3519         }                                                                                                
3520         return new ArrayList<ItemInfo>(filtered);                                                        
3521     }                                                                                                    
3522                                                                                                          
3523     @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                    
3524             final UserHandleCompat user) {                                                               
3525         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3526             @Override                                                                                    
3527             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3528                 if (info.user == null) {                                                                 
3529                     return cn.equals(cname);                                                             
3530                 } else {                                                                                 
3531                     return cn.equals(cname) && info.user.equals(user);                                   
3532                 }                                                                                        
3533             }                                                                                            
3534         };                                                                                               
3535         return filterItemInfos(sBgItemsIdMap, filter);                                                   
3536     }                                                                                                    
3537                                                                                                          
3538     /**                                                                                                  
3539      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3540      */                                                                                                  
3541     @Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,                                       
3542             int titleIndex, CursorIconInfo iconInfo) {                                                   
3543         final ShortcutInfo info = new ShortcutInfo();                                                    
3544         // Non-app shortcuts are only supported for current user.                                        
3545         info.user = UserHandleCompat.myUserHandle();                                                     
3546         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3547                                                                                                          
3548         // TODO: If there's an explicit component and we can't install that, delete it.                  
3549                                                                                                          
3550         info.title = Utilities.trim(c.getString(titleIndex));                                            
3551                                                                                                          
3552         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3553         // the fallback icon                                                                             
3554         if (icon == null) {                                                                              
3555             icon = mIconCache.getDefaultIcon(info.user);                                                 
3556             info.usingFallbackIcon = true;                                                               
3557         }                                                                                                
3558         info.setIcon(icon);                                                                              
3559         return info;                                                                                     
3560     }                                                                                                    
3561                                                                                                          
3562     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3563         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3564         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3565         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3566                                                                                                          
3567         if (intent == null) {                                                                            
3568             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3569             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3570             return null;                                                                                 
3571         }                                                                                                
3572                                                                                                          
3573         Bitmap icon = null;                                                                              
3574         boolean customIcon = false;                                                                      
3575         ShortcutIconResource iconResource = null;                                                        
3576                                                                                                          
3577         if (bitmap instanceof Bitmap) {                                                                  
3578             icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                 
3579             customIcon = true;                                                                           
3580         } else {                                                                                         
3581             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3582             if (extra instanceof ShortcutIconResource) {                                                 
3583                 iconResource = (ShortcutIconResource) extra;                                             
3584                 icon = Utilities.createIconBitmap(iconResource.packageName,                              
3585                         iconResource.resourceName, context);                                             
3586             }                                                                                            
3587         }                                                                                                
3588                                                                                                          
3589         final ShortcutInfo info = new ShortcutInfo();                                                    
3590                                                                                                          
3591         // Only support intents for current user for now. Intents sent from other                        
3592         // users wouldn't get here without intent forwarding anyway.                                     
3593         info.user = UserHandleCompat.myUserHandle();                                                     
3594         if (icon == null) {                                                                              
3595             icon = mIconCache.getDefaultIcon(info.user);                                                 
3596             info.usingFallbackIcon = true;                                                               
3597         }                                                                                                
3598         info.setIcon(icon);                                                                              
3599                                                                                                          
3600         info.title = Utilities.trim(name);                                                               
3601         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3602         info.intent = intent;                                                                            
3603         info.customIcon = customIcon;                                                                    
3604         info.iconResource = iconResource;                                                                
3605                                                                                                          
3606         return info;                                                                                     
3607     }                                                                                                    
3608                                                                                                          
3609     /**                                                                                                  
3610      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3611      * or make a new one.                                                                                
3612      */                                                                                                  
3613     @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {               
3614         // See if a placeholder was created for us already                                               
3615         FolderInfo folderInfo = folders.get(id);                                                         
3616         if (folderInfo == null) {                                                                        
3617             // No placeholder -- create a new instance                                                   
3618             folderInfo = new FolderInfo();                                                               
3619             folders.put(id, folderInfo);                                                                 
3620         }                                                                                                
3621         return folderInfo;                                                                               
3622     }                                                                                                    
3623                                                                                                          
3624                                                                                                          
3625     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3626         return (provider != null) && (provider.provider != null)                                         
3627                 && (provider.provider.getPackageName() != null);                                         
3628     }                                                                                                    
3629                                                                                                          
3630     public void dumpState() {                                                                            
3631         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3632         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3633         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3634         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3635         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3636         if (mLoaderTask != null) {                                                                       
3637             mLoaderTask.dumpState();                                                                     
3638         } else {                                                                                         
3639             Log.d(TAG, "mLoaderTask=null");                                                              
3640         }                                                                                                
3641     }                                                                                                    
3642                                                                                                          
3643     public Callbacks getCallback() {                                                                     
3644         return mCallbacks != null ? mCallbacks.get() : null;                                             
3645     }                                                                                                    
3646                                                                                                          
3647     /**                                                                                                  
3648      * @return {@link FolderInfo} if its already loaded.                                                 
3649      */                                                                                                  
3650     public FolderInfo findFolderById(Long folderId) {                                                    
3651         synchronized (sBgLock) {                                                                         
3652             return sBgFolders.get(folderId);                                                             
3653         }                                                                                                
3654     }                                                                                                    
3655                                                                                                          
3656     /**                                                                                                  
3657      * @return the looper for the worker thread which can be used to start background tasks.             
3658      */                                                                                                  
3659     public static Looper getWorkerLooper() {                                                             
3660         return sWorkerThread.getLooper();                                                                
3661     }                                                                                                    
3662 }                                                                                                        


































































































   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16 package com.android.launcher3;                                                                           
  17                                                                                                          
  18 import android.app.SearchManager;                                                                        
  19 import android.appwidget.AppWidgetProviderInfo;                                                          
  20 import android.content.BroadcastReceiver;                                                                
  21 import android.content.ComponentName;                                                                    
  22 import android.content.ContentProviderOperation;                                                         
  23 import android.content.ContentResolver;                                                                  
  24 import android.content.ContentValues;                                                                    
  25 import android.content.Context;                                                                          
  26 import android.content.Intent.ShortcutIconResource;                                                      
  27 import android.content.Intent;                                                                           
  28 import android.content.IntentFilter;                                                                     
  29 import android.content.pm.PackageManager;                                                                
  30 import android.content.pm.ProviderInfo;                                                                  
  31 import android.content.pm.ResolveInfo;                                                                   
  32 import android.database.Cursor;                                                                          
  33 import android.graphics.Bitmap;                                                                          
  34 import android.net.Uri;                                                                                  
  35 import android.os.Build;                                                                                 
  36 import android.os.Environment;                                                                           
  37 import android.os.Handler;                                                                               
  38 import android.os.HandlerThread;                                                                         
  39 import android.os.Looper;                                                                                
  40 import android.os.Parcelable;                                                                            
  41 import android.os.Process;                                                                               
  42 import android.os.SystemClock;                                                                           
  43 import android.os.TransactionTooLargeException;                                                          
  44 import android.provider.BaseColumns;                                                                     
  45 import android.text.TextUtils;                                                                           
  46 import android.util.Log;                                                                                 
  47 import android.util.LongSparseArray;                                                                     
  48 import android.util.Pair;                                                                                
  49 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  50 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  51 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  52 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  53 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  54 import com.android.launcher3.compat.UserHandleCompat;                                                    
  55 import com.android.launcher3.compat.UserManagerCompat;                                                   
  56 import com.android.launcher3.model.WidgetsModel;                                                         
  57 import com.android.launcher3.util.ComponentKey;                                                          
  58 import com.android.launcher3.util.CursorIconInfo;                                                        
  59 import com.android.launcher3.util.LongArrayMap;                                                          
  60 import com.android.launcher3.util.ManagedProfileHeuristic;                                               
  61 import com.android.launcher3.util.Thunk;                                                                 
  62 import java.lang.ref.WeakReference;                                                                      
  63 import java.net.URISyntaxException;                                                                      
  64 import java.security.InvalidParameterException;                                                          
  65 import java.util.ArrayList;                                                                              
  66 import java.util.Arrays;                                                                                 
  67 import java.util.Collection;                                                                             
  68 import java.util.Collections;                                                                            
  69 import java.util.Comparator;                                                                             
  70 import java.util.HashMap;                                                                                
  71 import java.util.HashSet;                                                                                
  72 import java.util.Iterator;                                                                               
  73 import java.util.List;                                                                                   
  74 import java.util.Map.Entry;                                                                              
  75 import java.util.Set;                                                                                    
  76                                                                                                          
  77                                                                                                          
  78 /**                                                                                                      
  79  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  80  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  81  * for the Launcher.                                                                                     
  82  */                                                                                                      
  83 public class LauncherModel extends BroadcastReceiver implements LauncherAppsCompat.OnAppsChangedCallbackC🔵
  84     static final boolean DEBUG_LOADERS = false;                                                          
  85                                                                                                          
  86     private static final boolean DEBUG_RECEIVER = false;                                                 
  87                                                                                                          
  88     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  89                                                                                                          
  90     static final String TAG = "Launcher.Model";                                                          
  91                                                                                                          
  92     public static final int LOADER_FLAG_NONE = 0;                                                        
  93                                                                                                          
  94     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  95                                                                                                          
  96     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  97                                                                                                          
  98     // batch size for the workspace icons                                                                
  99     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
 100                                                                                                          
 101     private static final long INVALID_SCREEN_ID = -1L;                                                   
 102                                                                                                          
 103     @Thunk                                                                                               
 104     final boolean mAppsCanBeOnRemoveableStorage;                                                         
 105                                                                                                          
 106     private final boolean mOldContentProviderExists;                                                     
 107                                                                                                          
 108     @Thunk                                                                                               
 109     final LauncherAppState mApp;                                                                         
 110                                                                                                          
 111     @Thunk                                                                                               
 112     final Object mLock = new Object();                                                                   
 113                                                                                                          
 114     @Thunk                                                                                               
 115     DeferredHandler mHandler = new DeferredHandler();                                                    
 116                                                                                                          
 117     @Thunk                                                                                               
 118     LoaderTask mLoaderTask;                                                                              
 119                                                                                                          
 120     @Thunk                                                                                               
 121     boolean mIsLoaderTaskRunning;                                                                        
 122                                                                                                          
 123     @Thunk                                                                                               
 124     boolean mHasLoaderCompletedOnce;                                                                     
 125                                                                                                          
 126     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 127                                                                                                          
 128     @Thunk                                                                                               
 129     static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                     
 130                                                                                                          
 131     static {                                                                                             
 132         sWorkerThread.start();                                                                           
 133     }                                                                                                    
 134                                                                                                          
 135     @Thunk                                                                                               
 136     static final Handler sWorker = new Handler(sWorkerThread.getLooper());                               
 137                                                                                                          
 138     // We start off with everything not loaded.  After that, we assume that                              
 139     // our monitoring of the package manager provides all updates and we never                           
 140     // need to do a requery.  These are only ever touched from the loader thread.                        
 141     @Thunk                                                                                               
 142     boolean mWorkspaceLoaded;                                                                            
 143                                                                                                          
 144     @Thunk                                                                                               
 145     boolean mAllAppsLoaded;                                                                              
 146                                                                                                          
 147     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 148     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 149     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 150     // a normal load, we also clear this set of Runnables.                                               
 151     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 152                                                                                                          
 153     /**                                                                                                  
 154      * Set of runnables to be called on the background thread after the workspace binding                
 155      * is complete.                                                                                      
 156      */                                                                                                  
 157     static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();                 
 158                                                                                                          
 159     @Thunk                                                                                               
 160     WeakReference<Callbacks> mCallbacks;                                                                 
 161                                                                                                          
 162     // < only access in worker thread >                                                                  
 163     // < only access in worker thread >                                                                  
 164     AllAppsList mBgAllAppsList;                                                                          
 165                                                                                                          
 166     // Entire list of widgets.                                                                           
 167     // Entire list of widgets.                                                                           
 168     WidgetsModel mBgWidgetsModel;                                                                        
 169                                                                                                          
 170     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 171     // other locks, this one can generally be held long-term because we never expect any of these        
 172     // static data structures to be referenced outside of the worker thread except on the first          
 173     // load after configuration change.                                                                  
 174     static final Object sBgLock = new Object();                                                          
 175                                                                                                          
 176     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 177     // LauncherModel to their ids                                                                        
 178     static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();                            
 179                                                                                                          
 180     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 181     // created by LauncherModel that are directly on the home screen (however, no widgets or             
 182     // shortcuts within folders).                                                                        
 183     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 184                                                                                                          
 185     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 186     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 187     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 188         new ArrayList<LauncherAppWidgetInfo>();                                                          
 189                                                                                                          
 190     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 191     static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();                             
 192                                                                                                          
 193     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 194     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 195     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 196                                                                                                          
 197     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 198     public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;               
 199                                                                                                          
 200     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 201     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages = new HashMap<UserHandleComp🔵
 202                                                                                                          
 203     // </ only access in worker thread >                                                                 
 204     @Thunk                                                                                               
 205     IconCache mIconCache;                                                                                
 206                                                                                                          
 207     @Thunk                                                                                               
 208     final LauncherAppsCompat mLauncherApps;                                                              
 209                                                                                                          
 210     @Thunk                                                                                               
 211     final UserManagerCompat mUserManager;                                                                
 212                                                                                                          
 213     public interface Callbacks {                                                                         
 214         public boolean setLoadOnResume();                                                                
 215                                                                                                          
 216         public int getCurrentWorkspaceScreen();                                                          
 217                                                                                                          
 218         public void startBinding();                                                                      
 219                                                                                                          
 220         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 221                               boolean forceAnimateIcons);                                                
 222                                                                                                          
 223         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 224                                                                                                          
 225         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 226                                                                                                          
 227         public abstract void bindFolders(LongArrayMap<FolderInfo> folders);                              
 228                                                                                                          
 229         public abstract void finishBindingItems();                                                       
 230                                                                                                          
 231         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 232                                                                                                          
 233         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 234                                                                                                          
 235         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 236                                   ArrayList<ItemInfo> addNotAnimated,                                    
 237                                   ArrayList<ItemInfo> addAnimated,                                       
 238                                   ArrayList<AppInfo> addedApps);                                         
 239                                                                                                          
 240         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 241                                                                                                          
 242         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                
 243                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                 
 244                                                                                                          
 245         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                       
 246                                                                                                          
 247         public abstract void bindRestoreItemsChange(HashSet<ItemInfo> updates);                          
 248                                                                                                          
 249         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 250                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                 
 251                                                                                                          
 252         public abstract void bindAllPackages(WidgetsModel model);                                        
 253                                                                                                          
 254         public void bindSearchablesChanged();                                                            
 255                                                                                                          
 256         public boolean isAllAppsButtonRank(int rank);                                                    
 257                                                                                                          
 258         public void onPageBoundSynchronously(int page);                                                  
 259                                                                                                          
 260         public void dumpLogsToLocalData();                                                               
 261     }                                                                                                    
 262                                                                                                          
 263     public interface ItemInfoFilter {                                                                    
 264         public abstract boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);            
 265     }                                                                                                    
 266                                                                                                          
 267     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 268         Context context = app.getContext();                                                              
 269         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 270         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 271         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 272         // resource string.                                                                              
 273         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 274         ProviderInfo providerInfo = context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY,🔵
 275         ProviderInfo redirectProvider = context.getPackageManager().resolveContentProvider(redirectAuthor🔵
 276         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 277         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 278         if (mOldContentProviderExists) {                                                                 
 279             Log.d(TAG, "Old launcher provider exists.");                                                 
 280         } else {                                                                                         
 281             Log.d(TAG, "Old launcher provider does not exist.");                                         
 282         }                                                                                                
 283         mApp = app;                                                                                      
 284         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 285         mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);                               
 286         mIconCache = iconCache;                                                                          
 287         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 288         mUserManager = UserManagerCompat.getInstance(context);                                           
 289     }                                                                                                    
 290                                                                                                          
 291     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 292      * posted on the main thread handler. */                                                             
 293     @Thunk                                                                                               
 294     void runOnMainThread(Runnable r) {                                                                   
 295         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 296             // If we are on the worker thread, post onto the main handler                                
 297             mHandler.post(r);                                                                            
 298         } else {                                                                                         
 299             r.run();                                                                                     
 300         }                                                                                                
 301     }                                                                                                    
 302                                                                                                          
 303     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 304      * posted on the worker thread handler. */                                                           
 305     private static void runOnWorkerThread(Runnable r) {                                                  
 306         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 307             r.run();                                                                                     
 308         } else {                                                                                         
 309             // If we are not on the worker thread, then post to the worker handler                       
 310             sWorker.post(r);                                                                             
 311         }                                                                                                
 312     }                                                                                                    
 313                                                                                                          
 314     /**                                                                                                  
 315      * Runs the specified runnable after the loader is complete                                          
 316      */                                                                                                  
 317     @Thunk                                                                                               
 318     void runAfterBindCompletes(Runnable r) {                                                             
 319         if (isLoadingWorkspace() || (!mHasLoaderCompletedOnce)) {                                        
 320             synchronized(mBindCompleteRunnables) {                                                       
 321                 mBindCompleteRunnables.add(r);                                                           
 322             }                                                                                            
 323         } else {                                                                                         
 324             runOnWorkerThread(r);                                                                        
 325         }                                                                                                
 326     }                                                                                                    
 327                                                                                                          
 328     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 329         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 330     }                                                                                                    
 331                                                                                                          
 332     public void setPackageState(final PackageInstallInfo installInfo) {                                  
 333         Runnable updateRunnable = new Runnable() {                                                       
 334             @Override                                                                                    
 335             public void run() {                                                                          
 336                 synchronized(sBgLock) {                                                                  
 337                     final HashSet<ItemInfo> updates = new HashSet<>();                                   
 338                     if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                  
 339                         // Ignore install success events as they are handled by Package add events.      
 340                         return;                                                                          
 341                     }                                                                                    
 342                     for (ItemInfo info : sBgItemsIdMap) {                                                
 343                         if (info instanceof ShortcutInfo) {                                              
 344                             ShortcutInfo si = ((ShortcutInfo) (info));                                   
 345                             ComponentName cn = si.getTargetComponent();                                  
 346                             if ((si.isPromise() && (cn != null)) && installInfo.packageName.equals(cn.get🔵
 347                                 si.setInstallProgress(installInfo.progress);                             
 348                                 if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {         
 349                                     // Mark this info as broken.                                         
 350                                     si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;              
 351                                 }                                                                        
 352                                 updates.add(si);                                                         
 353                             }                                                                            
 354                         }                                                                                
 355                     }                                                                                    
 356                     for (LauncherAppWidgetInfo widget : sBgAppWidgets) {                                 
 357                         if (widget.providerName.getPackageName().equals(installInfo.packageName)) {      
 358                             widget.installProgress = installInfo.progress;                               
 359                             updates.add(widget);                                                         
 360                         }                                                                                
 361                     }                                                                                    
 362                     if (!updates.isEmpty()) {                                                            
 363                         // Push changes to the callback.                                                 
 364                         Runnable r = new Runnable() {                                                    
 365                             public void run() {                                                          
 366                                 Callbacks callbacks = getCallback();                                     
 367                                 if (callbacks != null) {                                                 
 368                                     callbacks.bindRestoreItemsChange(updates);                           
 369                                 }                                                                        
 370                             }                                                                            
 371                         };                                                                               
 372                         mHandler.post(r);                                                                
 373                     }                                                                                    
 374                 }                                                                                        
 375             }                                                                                            
 376         };                                                                                               
 377         runOnWorkerThread(updateRunnable);                                                               
 378     }                                                                                                    
 379                                                                                                          
 380     /**                                                                                                  
 381      * Updates the icons and label of all pending icons for the provided package name.                   
 382      */                                                                                                  
 383     public void updateSessionDisplayInfo(final String packageName) {                                     
 384         Runnable updateRunnable = new Runnable() {                                                       
 385             @Override                                                                                    
 386             public void run() {                                                                          
 387                 synchronized(sBgLock) {                                                                  
 388                     final ArrayList<ShortcutInfo> updates = new ArrayList<>();                           
 389                     final UserHandleCompat user = UserHandleCompat.myUserHandle();                       
 390                     for (ItemInfo info : sBgItemsIdMap) {                                                
 391                         if (info instanceof ShortcutInfo) {                                              
 392                             ShortcutInfo si = ((ShortcutInfo) (info));                                   
 393                             ComponentName cn = si.getTargetComponent();                                  
 394                             if ((si.isPromise() && (cn != null)) && packageName.equals(cn.getPackageName(🔵
 395                                 if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {               
 396                                     // For auto install apps update the icon as well as label.           
 397                                     mIconCache.getTitleAndIcon(si, si.promisedIntent, user, si.shouldUseL🔵
 398                                 } else {                                                                 
 399                                     // Only update the icon for restored apps.                           
 400                                     si.updateIcon(mIconCache);                                           
 401                                 }                                                                        
 402                                 updates.add(si);                                                         
 403                             }                                                                            
 404                         }                                                                                
 405                     }                                                                                    
 406                     if (!updates.isEmpty()) {                                                            
 407                         // Push changes to the callback.                                                 
 408                         Runnable r = new Runnable() {                                                    
 409                             public void run() {                                                          
 410                                 Callbacks callbacks = getCallback();                                     
 411                                 if (callbacks != null) {                                                 
 412                                     callbacks.bindShortcutsChanged(updates, new ArrayList<ShortcutInfo>()🔵
 413                                 }                                                                        
 414                             }                                                                            
 415                         };                                                                               
 416                         mHandler.post(r);                                                                
 417                     }                                                                                    
 418                 }                                                                                        
 419             }                                                                                            
 420         };                                                                                               
 421         runOnWorkerThread(updateRunnable);                                                               
 422     }                                                                                                    
 423                                                                                                          
 424     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 425         final Callbacks callbacks = getCallback();                                                       
 426         if (allAppsApps == null) {                                                                       
 427             throw new RuntimeException("allAppsApps must not be null");                                  
 428         }                                                                                                
 429         if (allAppsApps.isEmpty()) {                                                                     
 430             return;                                                                                      
 431         }                                                                                                
 432         // Process the newly added applications and add them to the database first                       
 433         Runnable r = new Runnable() {                                                                    
 434             public void run() {                                                                          
 435                 runOnMainThread(new Runnable() {                                                         
 436                     public void run() {                                                                  
 437                         Callbacks cb = getCallback();                                                    
 438                         if ((callbacks == cb) && (cb != null)) {                                         
 439                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 440                         }                                                                                
 441                     }                                                                                    
 442                 });                                                                                      
 443             }                                                                                            
 444         };                                                                                               
 445         runOnWorkerThread(r);                                                                            
 446     }                                                                                                    
 447                                                                                                          
 448     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos, int[] xy, 🔵
 449         LauncherAppState app = LauncherAppState.getInstance();                                           
 450         InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                
 451         final int xCount = ((int) (profile.numColumns));                                                 
 452         final int yCount = ((int) (profile.numRows));                                                    
 453         boolean[][] occupied = new boolean[xCount][yCount];                                              
 454         if (occupiedPos != null) {                                                                       
 455             for (ItemInfo r : occupiedPos) {                                                             
 456                 int right = r.cellX + r.spanX;                                                           
 457                 int bottom = r.cellY + r.spanY;                                                          
 458                 for (int x = r.cellX; ((0 <= x) && (x < right)) && (x < xCount); x++) {                  
 459                     for (int y = r.cellY; ((0 <= y) && (y < bottom)) && (y < yCount); y++) {             
 460                         occupied[x][y] = true;                                                           
 461                     }                                                                                    
 462                 }                                                                                        
 463             }                                                                                            
 464         }                                                                                                
 465         return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                     
 466     }                                                                                                    
 467                                                                                                          
 468     /**                                                                                                  
 469      * Find a position on the screen for the given size or adds a new screen.                            
 470      * @return screenId and the coordinates for the item.                                                
 471      */                                                                                                  
 472     @Thunk                                                                                               
 473     Pair<Long, int[]> findSpaceForItem(Context context, ArrayList<Long> workspaceScreens, ArrayList<Long>🔵
 474         LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();                      
 475         // Use sBgItemsIdMap as all the items are already loaded.                                        
 476         assertWorkspaceLoaded();                                                                         
 477         synchronized(sBgLock) {                                                                          
 478             for (ItemInfo info : sBgItemsIdMap) {                                                        
 479                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
 480                     ArrayList<ItemInfo> items = screenItems.get(info.screenId);                          
 481                     if (items == null) {                                                                 
 482                         items = new ArrayList<>();                                                       
 483                         screenItems.put(info.screenId, items);                                           
 484                     }                                                                                    
 485                     items.add(info);                                                                     
 486                 }                                                                                        
 487             }                                                                                            
 488         }                                                                                                
 489         // Find appropriate space for the item.                                                          
 490         long screenId = 0;                                                                               
 491         int[] cordinates = new int[2];                                                                   
 492         boolean found = false;                                                                           
 493         int screenCount = workspaceScreens.size();                                                       
 494         // First check the preferred screen.                                                             
 495         int preferredScreenIndex = (workspaceScreens.isEmpty()) ? 0 : 1;                                 
 496         if (preferredScreenIndex < screenCount) {                                                        
 497             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 498             found = findNextAvailableIconSpaceInScreen(screenItems.get(screenId), cordinates, spanX, span🔵
 499         }                                                                                                
 500         if (!found) {                                                                                    
 501             // Search on any of the screens starting from the first screen.                              
 502             for (int screen = 1; screen < screenCount; screen++) {                                       
 503                 screenId = workspaceScreens.get(screen);                                                 
 504                 if (findNextAvailableIconSpaceInScreen(screenItems.get(screenId), cordinates, spanX, span🔵
 505                     // We found a space for it                                                           
 506                     found = true;                                                                        
 507                     break;                                                                               
 508                 }                                                                                        
 509             }                                                                                            
 510         }                                                                                                
 511         if (!found) {                                                                                    
 512             // Still no position found. Add a new screen to the end.                                     
 513             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 514             // Save the screen id for binding in the workspace                                           
 515             workspaceScreens.add(screenId);                                                              
 516             addedWorkspaceScreensFinal.add(screenId);                                                    
 517             // If we still can't find an empty space, then God help us all!!!                            
 518             if (!findNextAvailableIconSpaceInScreen(screenItems.get(screenId), cordinates, spanX, spanY))🔵
 519                 throw new RuntimeException("Can't find space to add the item");                          
 520             }                                                                                            
 521         }                                                                                                
 522         return Pair.create(screenId, cordinates);                                                        
 523     }                                                                                                    
 524                                                                                                          
 525     /**                                                                                                  
 526      * Adds the provided items to the workspace.                                                         
 527      */                                                                                                  
 528     public void addAndBindAddedWorkspaceItems(final Context context, final ArrayList<? extends ItemInfo> 🔵
 529         final Callbacks callbacks = getCallback();                                                       
 530         if (workspaceApps.isEmpty()) {                                                                   
 531             return;                                                                                      
 532         }                                                                                                
 533         // Process the newly added applications and add them to the database first                       
 534         Runnable r = new Runnable() {                                                                    
 535             public void run() {                                                                          
 536                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 537                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 538                 // Get the list of workspace screens.  We need to append to this list and                
 539                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 540                 // called.                                                                               
 541                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 542                 synchronized(sBgLock) {                                                                  
 543                     for (ItemInfo item : workspaceApps) {                                                
 544                         if (item instanceof ShortcutInfo) {                                              
 545                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 546                             if (shortcutExists(context, item.getIntent(), item.user)) {                  
 547                                 continue;                                                                
 548                             }                                                                            
 549                         }                                                                                
 550                         // Find appropriate space for the item.                                          
 551                         Pair<Long, int[]> coords = findSpaceForItem(context, workspaceScreens, addedWorks🔵
 552                         long screenId = coords.first;                                                    
 553                         int[] cordinates = coords.second;                                                
 554                         ItemInfo itemInfo;                                                               
 555                         if ((item instanceof ShortcutInfo) || (item instanceof FolderInfo)) {            
 556                             itemInfo = item;                                                             
 557                         } else if (item instanceof AppInfo) {                                            
 558                             itemInfo = ((AppInfo) (item)).makeShortcut();                                
 559                         } else {                                                                         
 560                             throw new RuntimeException("Unexpected info type");                          
 561                         }                                                                                
 562                         // Add the shortcut to the db                                                    
 563                         addItemToDatabase(context, itemInfo, LauncherSettings.Favorites.CONTAINER_DESKTOP🔵
 564                         // Save the ShortcutInfo for binding in the workspace                            
 565                         addedShortcutsFinal.add(itemInfo);                                               
 566                     }                                                                                    
 567                 }                                                                                        
 568                 // Update the workspace screens                                                          
 569                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 570                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 571                     runOnMainThread(new Runnable() {                                                     
 572                         public void run() {                                                              
 573                             Callbacks cb = getCallback();                                                
 574                             if ((callbacks == cb) && (cb != null)) {                                     
 575                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 576                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 577                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 578                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 579                                     long lastScreenId = info.screenId;                                   
 580                                     for (ItemInfo i : addedShortcutsFinal) {                             
 581                                         if (i.screenId == lastScreenId) {                                
 582                                             addAnimated.add(i);                                          
 583                                         } else {                                                         
 584                                             addNotAnimated.add(i);                                       
 585                                         }                                                                
 586                                     }                                                                    
 587                                 }                                                                        
 588                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal, addNotAnimated, addAn🔵
 589                             }                                                                            
 590                         }                                                                                
 591                     });                                                                                  
 592                 }                                                                                        
 593             }                                                                                            
 594         };                                                                                               
 595         runOnWorkerThread(r);                                                                            
 596     }                                                                                                    
 597                                                                                                          
 598     private void unbindItemInfosAndClearQueuedBindRunnables() {                                          
 599         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 600             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " + "mai🔵
 601         }                                                                                                
 602         // Clear any deferred bind runnables                                                             
 603         synchronized(mDeferredBindRunnables) {                                                           
 604             mDeferredBindRunnables.clear();                                                              
 605         }                                                                                                
 606         // Remove any queued UI runnables                                                                
 607         mHandler.cancelAll();                                                                            
 608         // Unbind all the workspace items                                                                
 609         unbindWorkspaceItemsOnMainThread();                                                              
 610     }                                                                                                    
 611                                                                                                          
 612     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 613     void unbindWorkspaceItemsOnMainThread() {                                                            
 614         // Ensure that we don't use the same workspace items data structure on the main thread           
 615         // by making a copy of workspace items first.                                                    
 616         final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();                                  
 617         synchronized(sBgLock) {                                                                          
 618             tmpItems.addAll(sBgWorkspaceItems);                                                          
 619             tmpItems.addAll(sBgAppWidgets);                                                              
 620         }                                                                                                
 621         Runnable r = new Runnable() {                                                                    
 622             @Override                                                                                    
 623             public void run() {                                                                          
 624                 for (ItemInfo item : tmpItems) {                                                         
 625                     item.unbind();                                                                       
 626                 }                                                                                        
 627             }                                                                                            
 628         };                                                                                               
 629         runOnMainThread(r);                                                                              
 630     }                                                                                                    
 631                                                                                                          
 632     /**                                                                                                  
 633      * Adds an item to the DB if it was not created previously, or move it to a new                      
 634      * <container, screen, cellX, cellY>                                                                 
 635      */                                                                                                  
 636     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container, long screenId, in🔵
 637         if (item.container == ItemInfo.NO_ID) {                                                          
 638             // From all apps                                                                             
 639             addItemToDatabase(context, item, container, screenId, cellX, cellY);                         
 640         } else {                                                                                         
 641             // From somewhere else                                                                       
 642             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 643         }                                                                                                
 644     }                                                                                                    
 645                                                                                                          
 646     static void checkItemInfoLocked(final long itemId, final ItemInfo item, StackTraceElement[] stackTrac🔵
 647         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 648         if ((modelItem != null) && (item != modelItem)) {                                                
 649             // check all the data is consistent                                                          
 650             if ((modelItem instanceof ShortcutInfo) && (item instanceof ShortcutInfo)) {                 
 651                 ShortcutInfo modelShortcut = ((ShortcutInfo) (modelItem));                               
 652                 ShortcutInfo shortcut = ((ShortcutInfo) (item));                                         
 653                 if ((((((((((modelShortcut.title.toString().equals(shortcut.title.toString()) && modelSho🔵
 654                     // For all intents and purposes, this is the same object                             
 655                     return;                                                                              
 656                 }                                                                                        
 657             }                                                                                            
 658             // the modelItem needs to match up perfectly with item if our model is                       
 659             // to be consistent with the database-- for now, just require                                
 660             // modelItem == item or the equality check above                                             
 661             String msg = ((("item: " + (item != null ? item.toString() : "null")) + "modelItem: ") + (mod🔵
 662             RuntimeException e = new RuntimeException(msg);                                              
 663             if (stackTrace != null) {                                                                    
 664                 e.setStackTrace(stackTrace);                                                             
 665             }                                                                                            
 666             throw e;                                                                                     
 667         }                                                                                                
 668     }                                                                                                    
 669                                                                                                          
 670     static void checkItemInfo(final ItemInfo item) {                                                     
 671         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 672         final long itemId = item.id;                                                                     
 673         Runnable r = new Runnable() {                                                                    
 674             public void run() {                                                                          
 675                 synchronized (sBgLock) {                                                                 
 676                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 677                 }                                                                                        
 678             }                                                                                            
 679         };                                                                                               
 680         runOnWorkerThread(r);                                                                            
 681     }                                                                                                    
 682                                                                                                          
 683     static void updateItemInDatabaseHelper(Context context, final ContentValues values, final ItemInfo it🔵
 684         final long itemId = item.id;                                                                     
 685         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                                
 686         final ContentResolver cr = context.getContentResolver();                                         
 687         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 688         Runnable r = new Runnable() {                                                                    
 689             public void run() {                                                                          
 690                 cr.update(uri, values, null, null);                                                      
 691                 updateItemArrays(item, itemId, stackTrace);                                              
 692             }                                                                                            
 693         };                                                                                               
 694         runOnWorkerThread(r);                                                                            
 695     }                                                                                                    
 696                                                                                                          
 697     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList, f🔵
 698         final ContentResolver cr = context.getContentResolver();                                         
 699         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 700         Runnable r = new Runnable() {                                                                    
 701             public void run() {                                                                          
 702                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
 703                 int count = items.size();                                                                
 704                 for (int i = 0; i < count; i++) {                                                        
 705                     ItemInfo item = items.get(i);                                                        
 706                     final long itemId = item.id;                                                         
 707                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                    
 708                     ContentValues values = valuesList.get(i);                                            
 709                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 710                     updateItemArrays(item, itemId, stackTrace);                                          
 711                 }                                                                                        
 712                 try {                                                                                    
 713                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 714                 } catch (java.lang.Exception e) {                                                        
 715                     e.printStackTrace();                                                                 
 716                 }                                                                                        
 717             }                                                                                            
 718         };                                                                                               
 719         runOnWorkerThread(r);                                                                            
 720     }                                                                                                    
 721                                                                                                          
 722     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 723         // Lock on mBgLock *after* the db operation                                                      
 724         synchronized(sBgLock) {                                                                          
 725             checkItemInfoLocked(itemId, item, stackTrace);                                               
 726             if ((item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) && (item.container != La🔵
 727                 // Item is in a folder, make sure this folder exists                                     
 728                 if (!sBgFolders.containsKey(item.container)) {                                           
 729                     // An items container is being set to a that of an item which is not in              
 730                     // the list of Folders.                                                              
 731                     String msg = ((("item: " + item) + " container being set to: ") + item.container) + "🔵
 732                     Log.e(TAG, msg);                                                                     
 733                 }                                                                                        
 734             }                                                                                            
 735             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 736             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 737             // that are on the desktop, as appropriate                                                   
 738             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 739             if ((modelItem != null) && ((modelItem.container == LauncherSettings.Favorites.CONTAINER_DESK🔵
 740                 switch (modelItem.itemType) {                                                            
 741                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                              
 742                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                                 
 743                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                                   
 744                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 745                             sBgWorkspaceItems.add(modelItem);                                            
 746                         }                                                                                
 747                         break;                                                                           
 748                     default :                                                                            
 749                         break;                                                                           
 750                 }                                                                                        
 751             } else {                                                                                     
 752                 sBgWorkspaceItems.remove(modelItem);                                                     
 753             }                                                                                            
 754         }                                                                                                
 755     }                                                                                                    
 756                                                                                                          
 757     /**                                                                                                  
 758      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 759      */                                                                                                  
 760     public static void moveItemInDatabase(Context context, final ItemInfo item, final long container, fin🔵
 761         item.container = container;                                                                      
 762         item.cellX = cellX;                                                                              
 763         item.cellY = cellY;                                                                              
 764         // We store hotseat items in canonical form which is this orientation invariant position         
 765         // in the hotseat                                                                                
 766         if (((context instanceof Launcher) && (screenId < 0)) && (container == LauncherSettings.Favorites🔵
 767             item.screenId = ((Launcher) (context)).getHotseat().getOrderInHotseat(cellX, cellY);         
 768         } else {                                                                                         
 769             item.screenId = screenId;                                                                    
 770         }                                                                                                
 771         final ContentValues values = new ContentValues();                                                
 772         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 773         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 774         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 775         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 776         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 777         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 778     }                                                                                                    
 779                                                                                                          
 780     /**                                                                                                  
 781      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 782      * cellX, cellY have already been updated on the ItemInfos.                                          
 783      */                                                                                                  
 784     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 785             final long container, final int screen) {                                                    
 786                                                                                                          
 787         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 788         int count = items.size();                                                                        
 789                                                                                                          
 790         for (int i = 0; i < count; i++) {                                                                
 791             ItemInfo item = items.get(i);                                                                
 792             item.container = container;                                                                  
 793                                                                                                          
 794             // We store hotseat items in canonical form which is this orientation invariant position     
 795             // in the hotseat                                                                            
 796             if (context instanceof Launcher && screen < 0 &&                                             
 797                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 798                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 799                         item.cellY);                                                                     
 800             } else {                                                                                     
 801                 item.screenId = screen;                                                                  
 802             }                                                                                            
 803                                                                                                          
 804             final ContentValues values = new ContentValues();                                            
 805             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 806             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 807             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 808             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 809             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 810                                                                                                          
 811             contentValues.add(values);                                                                   
 812         }                                                                                                
 813         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 814     }                                                                                                    
 815                                                                                                          
 816     /**                                                                                                  
 817      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 818      */                                                                                                  
 819     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 820             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 821         item.container = container;                                                                      
 822         item.cellX = cellX;                                                                              
 823         item.cellY = cellY;                                                                              
 824         item.spanX = spanX;                                                                              
 825         item.spanY = spanY;                                                                              
 826                                                                                                          
 827         // We store hotseat items in canonical form which is this orientation invariant position         
 828         // in the hotseat                                                                                
 829         if (context instanceof Launcher && screenId < 0 &&                                               
 830                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 831             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 832         } else {                                                                                         
 833             item.screenId = screenId;                                                                    
 834         }                                                                                                
 835                                                                                                          
 836         final ContentValues values = new ContentValues();                                                
 837         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 838         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 839         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 840         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 841         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 842         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 843         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 844                                                                                                          
 845         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 846     }                                                                                                    
 847                                                                                                          
 848     /**                                                                                                  
 849      * Update an item to the database in a specified container.                                          
 850      */                                                                                                  
 851     public static void updateItemInDatabase(Context context, final ItemInfo item) {                      
 852         final ContentValues values = new ContentValues();                                                
 853         item.onAddToDatabase(context, values);                                                           
 854         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 855     }                                                                                                    
 856                                                                                                          
 857     private void assertWorkspaceLoaded() {                                                               
 858         if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) {   
 859             throw new RuntimeException("Trying to add shortcut while loader is running");                
 860         }                                                                                                
 861     }                                                                                                    
 862                                                                                                          
 863     /**                                                                                                  
 864      * Returns true if the shortcuts already exists on the workspace. This must be called after          
 865      * the workspace has been loaded. We identify a shortcut by its intent.                              
 866      */                                                                                                  
 867     @Thunk                                                                                               
 868     boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {                      
 869         assertWorkspaceLoaded();                                                                         
 870         final String intentWithPkg;                                                                      
 871         final String intentWithoutPkg;                                                                   
 872         if (intent.getComponent() != null) {                                                             
 873             // If component is not null, an intent with null package will produce                        
 874             // the same result and should also be a match.                                               
 875             String packageName = intent.getComponent().getPackageName();                                 
 876             if (intent.getPackage() != null) {                                                           
 877                 intentWithPkg = intent.toUri(0);                                                         
 878                 intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);                         
 879             } else {                                                                                     
 880                 intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);                     
 881                 intentWithoutPkg = intent.toUri(0);                                                      
 882             }                                                                                            
 883         } else {                                                                                         
 884             intentWithPkg = intent.toUri(0);                                                             
 885             intentWithoutPkg = intent.toUri(0);                                                          
 886         }                                                                                                
 887         synchronized(sBgLock) {                                                                          
 888             for (ItemInfo item : sBgItemsIdMap) {                                                        
 889                 if (item instanceof ShortcutInfo) {                                                      
 890                     ShortcutInfo info = ((ShortcutInfo) (item));                                         
 891                     Intent targetIntent = (info.promisedIntent == null) ? info.intent : info.promisedInte🔵
 892                     if ((targetIntent != null) && info.user.equals(user)) {                              
 893                         String s = targetIntent.toUri(0);                                                
 894                         if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {                     
 895                             return true;                                                                 
 896                         }                                                                                
 897                     }                                                                                    
 898                 }                                                                                        
 899             }                                                                                            
 900         }                                                                                                
 901         return false;                                                                                    
 902     }                                                                                                    
 903                                                                                                          
 904     /**                                                                                                  
 905      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 906      */                                                                                                  
 907     FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {            
 908         final ContentResolver cr = context.getContentResolver();                                         
 909         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null, "_id=? and (itemType=? or itemT🔵
 910         try {                                                                                            
 911             if (c.moveToFirst()) {                                                                       
 912                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 913                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 914                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 915                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 916                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 917                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 918                 final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);    
 919                 FolderInfo folderInfo = null;                                                            
 920                 switch (c.getInt(itemTypeIndex)) {                                                       
 921                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                                   
 922                         folderInfo = findOrMakeFolder(folderList, id);                                   
 923                         break;                                                                           
 924                 }                                                                                        
 925                 // Do not trim the folder label, as is was set by the user.                              
 926                 folderInfo.title = c.getString(titleIndex);                                              
 927                 folderInfo.id = id;                                                                      
 928                 folderInfo.container = c.getInt(containerIndex);                                         
 929                 folderInfo.screenId = c.getInt(screenIndex);                                             
 930                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 931                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 932                 folderInfo.options = c.getInt(optionsIndex);                                             
 933                 return folderInfo;                                                                       
 934             }                                                                                            
 935         } finally {                                                                                      
 936             c.close();                                                                                   
 937         }                                                                                                
 938         return null;                                                                                     
 939     }                                                                                                    
 940                                                                                                          
 941     /**                                                                                                  
 942      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 943      * cellY fields of the item. Also assigns an ID to the item.                                         
 944      */                                                                                                  
 945     public static void addItemToDatabase(Context context, final ItemInfo item, final long container, fina🔵
 946         item.container = container;                                                                      
 947         item.cellX = cellX;                                                                              
 948         item.cellY = cellY;                                                                              
 949         // We store hotseat items in canonical form which is this orientation invariant position         
 950         // in the hotseat                                                                                
 951         if (((context instanceof Launcher) && (screenId < 0)) && (container == LauncherSettings.Favorites🔵
 952             item.screenId = ((Launcher) (context)).getHotseat().getOrderInHotseat(cellX, cellY);         
 953         } else {                                                                                         
 954             item.screenId = screenId;                                                                    
 955         }                                                                                                
 956         final ContentValues values = new ContentValues();                                                
 957         final ContentResolver cr = context.getContentResolver();                                         
 958         item.onAddToDatabase(context, values);                                                           
 959         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
 960         values.put(LauncherSettings.Favorites._ID, item.id);                                             
 961         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 962         Runnable r = new Runnable() {                                                                    
 963             public void run() {                                                                          
 964                 cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);                               
 965                 // Lock on mBgLock *after* the db operation                                              
 966                 synchronized(sBgLock) {                                                                  
 967                     checkItemInfoLocked(item.id, item, stackTrace);                                      
 968                     sBgItemsIdMap.put(item.id, item);                                                    
 969                     switch (item.itemType) {                                                             
 970                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                               
 971                             sBgFolders.put(item.id, ((FolderInfo) (item)));                              
 972                             // Fall through                                                              
 973                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                          
 974                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                             
 975                             if ((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) || (item🔵
 976                                 sBgWorkspaceItems.add(item);                                             
 977                             } else if (!sBgFolders.containsKey(item.container)) {                        
 978                                 // Adding an item to a folder that doesn't exist.                        
 979                                 String msg = (("adding item: " + item) + " to a folder that ") + " doesn'🔵
 980                                 Log.e(TAG, msg);                                                         
 981                             }                                                                            
 982                             break;                                                                       
 983                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                            
 984                             sBgAppWidgets.add(((LauncherAppWidgetInfo) (item)));                         
 985                             break;                                                                       
 986                     }                                                                                    
 987                 }                                                                                        
 988             }                                                                                            
 989         };                                                                                               
 990         runOnWorkerThread(r);                                                                            
 991     }                                                                                                    
 992                                                                                                          
 993     /**                                                                                                  
 994      * Creates a new unique child id, for a given cell span across all layouts.                          
 995      */                                                                                                  
 996     static int getCellLayoutChildId(                                                                     
 997             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
 998         return (((int) container & 0xFF) << 24)                                                          
 999                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1000     }                                                                                                    
1001                                                                                                          
1002     private static ArrayList<ItemInfo> getItemsByPackageName(final String pn, final UserHandleCompat user🔵
1003         ItemInfoFilter filter = new ItemInfoFilter() {                                                   
1004             @Override                                                                                    
1005             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1006                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1007             }                                                                                            
1008         };                                                                                               
1009         return filterItemInfos(sBgItemsIdMap, filter);                                                   
1010     }                                                                                                    
1011                                                                                                          
1012     /**                                                                                                  
1013      * Removes all the items from the database corresponding to the specified package.                   
1014      */                                                                                                  
1015     static void deletePackageFromDatabase(Context context, final String pn,                              
1016             final UserHandleCompat user) {                                                               
1017         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1018     }                                                                                                    
1019                                                                                                          
1020     /**                                                                                                  
1021      * Removes the specified item from the database                                                      
1022      * @param context                                                                                    
1023      * @param item                                                                                       
1024      */                                                                                                  
1025     public static void deleteItemFromDatabase(Context context, final ItemInfo item) {                    
1026         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1027         items.add(item);                                                                                 
1028         deleteItemsFromDatabase(context, items);                                                         
1029     }                                                                                                    
1030                                                                                                          
1031     /**                                                                                                  
1032      * Removes the specified items from the database                                                     
1033      * @param context                                                                                    
1034      * @param item                                                                                       
1035      */                                                                                                  
1036     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1037         final ContentResolver cr = context.getContentResolver();                                         
1038         Runnable r = new Runnable() {                                                                    
1039             public void run() {                                                                          
1040                 for (ItemInfo item : items) {                                                            
1041                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);                   
1042                     cr.delete(uri, null, null);                                                          
1043                     // Lock on mBgLock *after* the db operation                                          
1044                     synchronized(sBgLock) {                                                              
1045                         switch (item.itemType) {                                                         
1046                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                           
1047                                 sBgFolders.remove(item.id);                                              
1048                                 for (ItemInfo info : sBgItemsIdMap) {                                    
1049                                     if (info.container == item.id) {                                     
1050                                         // We are deleting a folder which still contains items that      
1051                                         // think they are contained by that folder.                      
1052                                         String msg = (((("deleting a folder (" + item) + ") which still "🔵
1053                                         Log.e(TAG, msg);                                                 
1054                                     }                                                                    
1055                                 }                                                                        
1056                                 sBgWorkspaceItems.remove(item);                                          
1057                                 break;                                                                   
1058                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                      
1059                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                         
1060                                 sBgWorkspaceItems.remove(item);                                          
1061                                 break;                                                                   
1062                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                        
1063                                 sBgAppWidgets.remove(((LauncherAppWidgetInfo) (item)));                  
1064                                 break;                                                                   
1065                         }                                                                                
1066                         sBgItemsIdMap.remove(item.id);                                                   
1067                     }                                                                                    
1068                 }                                                                                        
1069             }                                                                                            
1070         };                                                                                               
1071         runOnWorkerThread(r);                                                                            
1072     }                                                                                                    
1073                                                                                                          
1074     /**                                                                                                  
1075      * Update the order of the workspace screens in the database. The array list contains                
1076      * a list of screen ids in the order that they should appear.                                        
1077      */                                                                                                  
1078     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1079         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1080         final ContentResolver cr = context.getContentResolver();                                         
1081         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1082         // Remove any negative screen ids -- these aren't persisted                                      
1083         Iterator<Long> iter = screensCopy.iterator();                                                    
1084         while (iter.hasNext()) {                                                                         
1085             long id = iter.next();                                                                       
1086             if (id < 0) {                                                                                
1087                 iter.remove();                                                                           
1088             }                                                                                            
1089         }                                                                                                
1090         Runnable r = new Runnable() {                                                                    
1091             @Override                                                                                    
1092             public void run() {                                                                          
1093                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1094                 // Clear the table                                                                       
1095                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1096                 int count = screensCopy.size();                                                          
1097                 for (int i = 0; i < count; i++) {                                                        
1098                     ContentValues v = new ContentValues();                                               
1099                     long screenId = screensCopy.get(i);                                                  
1100                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1101                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1102                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1103                 }                                                                                        
1104                 try {                                                                                    
1105                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1106                 } catch (java.lang.Exception ex) {                                                       
1107                     throw new RuntimeException(ex);                                                      
1108                 }                                                                                        
1109                 synchronized(sBgLock) {                                                                  
1110                     sBgWorkspaceScreens.clear();                                                         
1111                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1112                 }                                                                                        
1113             }                                                                                            
1114         };                                                                                               
1115         runOnWorkerThread(r);                                                                            
1116     }                                                                                                    
1117                                                                                                          
1118     /**                                                                                                  
1119      * Remove the contents of the specified folder from the database                                     
1120      */                                                                                                  
1121     public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {        
1122         final ContentResolver cr = context.getContentResolver();                                         
1123         Runnable r = new Runnable() {                                                                    
1124             public void run() {                                                                          
1125                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);                
1126                 // Lock on mBgLock *after* the db operation                                              
1127                 synchronized(sBgLock) {                                                                  
1128                     sBgItemsIdMap.remove(info.id);                                                       
1129                     sBgFolders.remove(info.id);                                                          
1130                     sBgWorkspaceItems.remove(info);                                                      
1131                 }                                                                                        
1132                 cr.delete(LauncherSettings.Favorites.CONTENT_URI, (LauncherSettings.Favorites.CONTAINER +🔵
1133                 // Lock on mBgLock *after* the db operation                                              
1134                 synchronized(sBgLock) {                                                                  
1135                     for (ItemInfo childInfo : info.contents) {                                           
1136                         sBgItemsIdMap.remove(childInfo.id);                                              
1137                     }                                                                                    
1138                 }                                                                                        
1139             }                                                                                            
1140         };                                                                                               
1141         runOnWorkerThread(r);                                                                            
1142     }                                                                                                    
1143                                                                                                          
1144     /**                                                                                                  
1145      * Set this as the current Launcher activity object for the loader.                                  
1146      */                                                                                                  
1147     public void initialize(Callbacks callbacks) {                                                        
1148         synchronized(mLock) {                                                                            
1149             // Disconnect any of the callbacks and drawables associated with ItemInfos on the            
1150             // workspace to prevent leaking Launcher activities on orientation change.                   
1151             unbindItemInfosAndClearQueuedBindRunnables();                                                
1152             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1153         }                                                                                                
1154     }                                                                                                    
1155                                                                                                          
1156     @Override                                                                                            
1157     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1158         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1159         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1160                 user));                                                                                  
1161     }                                                                                                    
1162                                                                                                          
1163     @Override                                                                                            
1164     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1165         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1166         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1167                 user));                                                                                  
1168     }                                                                                                    
1169                                                                                                          
1170     @Override                                                                                            
1171     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1172         int op = PackageUpdatedTask.OP_ADD;                                                              
1173         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1174                 user));                                                                                  
1175     }                                                                                                    
1176                                                                                                          
1177     @Override                                                                                            
1178     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1179             boolean replacing) {                                                                         
1180         if (!replacing) {                                                                                
1181             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1182                     user));                                                                              
1183             if (mAppsCanBeOnRemoveableStorage) {                                                         
1184                 // Only rebind if we support removable storage. It catches the                           
1185                 // case where                                                                            
1186                 // apps on the external sd card need to be reloaded                                      
1187                 startLoaderFromBackground();                                                             
1188             }                                                                                            
1189         } else {                                                                                         
1190             // If we are replacing then just update the packages in the list                             
1191             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1192                     packageNames, user));                                                                
1193         }                                                                                                
1194     }                                                                                                    
1195                                                                                                          
1196     @Override                                                                                            
1197     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1198             boolean replacing) {                                                                         
1199         if (!replacing) {                                                                                
1200             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1201                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1202                     user));                                                                              
1203         }                                                                                                
1204     }                                                                                                    
1205                                                                                                          
1206     /**                                                                                                  
1207      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1208      * ACTION_PACKAGE_CHANGED.                                                                           
1209      */                                                                                                  
1210     @Override                                                                                            
1211     public void onReceive(Context context, Intent intent) {                                              
1212         if (DEBUG_RECEIVER) {                                                                            
1213             Log.d(TAG, "onReceive intent=" + intent);                                                    
1214         }                                                                                                
1215         final String action = intent.getAction();                                                        
1216         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1217             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1218             forceReload();                                                                               
1219         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) || SearchManager.IN🔵
1220             Callbacks callbacks = getCallback();                                                         
1221             if (callbacks != null) {                                                                     
1222                 callbacks.bindSearchablesChanged();                                                      
1223             }                                                                                            
1224         } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action) || LauncherAppsCompat.A🔵
1225             forceReload();                                                                               
1226         }                                                                                                
1227     }                                                                                                    
1228                                                                                                          
1229     void forceReload() {                                                                                 
1230         resetLoadedState(true, true);                                                                    
1231                                                                                                          
1232         // Do this here because if the launcher activity is running it will be restarted.                
1233         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1234         // to reload.                                                                                    
1235         startLoaderFromBackground();                                                                     
1236     }                                                                                                    
1237                                                                                                          
1238     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1239         synchronized(mLock) {                                                                            
1240             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1241             // mWorkspaceLoaded to true later                                                            
1242             stopLoaderLocked();                                                                          
1243             if (resetAllAppsLoaded) {                                                                    
1244                 mAllAppsLoaded = false;                                                                  
1245             }                                                                                            
1246             if (resetWorkspaceLoaded) {                                                                  
1247                 mWorkspaceLoaded = false;                                                                
1248             }                                                                                            
1249         }                                                                                                
1250     }                                                                                                    
1251                                                                                                          
1252     /**                                                                                                  
1253      * When the launcher is in the background, it's possible for it to miss paired                       
1254      * configuration changes.  So whenever we trigger the loader from the background                     
1255      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1256      * of doing it now.                                                                                  
1257      */                                                                                                  
1258     public void startLoaderFromBackground() {                                                            
1259         boolean runLoader = false;                                                                       
1260         Callbacks callbacks = getCallback();                                                             
1261         if (callbacks != null) {                                                                         
1262             // Only actually run the loader if they're not paused.                                       
1263             if (!callbacks.setLoadOnResume()) {                                                          
1264                 runLoader = true;                                                                        
1265             }                                                                                            
1266         }                                                                                                
1267         if (runLoader) {                                                                                 
1268             startLoader(PagedView.INVALID_RESTORE_PAGE);                                                 
1269         }                                                                                                
1270     }                                                                                                    
1271                                                                                                          
1272     /**                                                                                                  
1273      * If there is already a loader task running, tell it to stop.                                       
1274      */                                                                                                  
1275     private void stopLoaderLocked() {                                                                    
1276         LoaderTask oldTask = mLoaderTask;                                                                
1277         if (oldTask != null) {                                                                           
1278             oldTask.stopLocked();                                                                        
1279         }                                                                                                
1280     }                                                                                                    
1281                                                                                                          
1282     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1283         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1284     }                                                                                                    
1285                                                                                                          
1286     public void startLoader(int synchronousBindPage) {                                                   
1287         startLoader(synchronousBindPage, LOADER_FLAG_NONE);                                              
1288     }                                                                                                    
1289                                                                                                          
1290     public void startLoader(int synchronousBindPage, int loadFlags) {                                    
1291         // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems      
1292         InstallShortcutReceiver.enableInstallQueue();                                                    
1293         synchronized(mLock) {                                                                            
1294             // Clear any deferred bind-runnables from the synchronized load process                      
1295             // We must do this before any loading/binding is scheduled below.                            
1296             synchronized(mDeferredBindRunnables) {                                                       
1297                 mDeferredBindRunnables.clear();                                                          
1298             }                                                                                            
1299             // Don't bother to start the thread if we know it's not going to do anything                 
1300             if ((mCallbacks != null) && (mCallbacks.get() != null)) {                                    
1301                 // If there is already one running, tell it to stop.                                     
1302                 stopLoaderLocked();                                                                      
1303                 mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);                              
1304                 if ((((synchronousBindPage != PagedView.INVALID_RESTORE_PAGE) && mAllAppsLoaded) && mWork🔵
1305                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1306                 } else {                                                                                 
1307                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1308                     sWorker.post(mLoaderTask);                                                           
1309                 }                                                                                        
1310             }                                                                                            
1311         }                                                                                                
1312     }                                                                                                    
1313                                                                                                          
1314     void bindRemainingSynchronousPages() {                                                               
1315         // Post the remaining side pages to be loaded                                                    
1316         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1317             Runnable[] deferredBindRunnables = null;                                                     
1318             synchronized(mDeferredBindRunnables) {                                                       
1319                 deferredBindRunnables = mDeferredBindRunnables.toArray(new Runnable[mDeferredBindRunnable🔵
1320                 mDeferredBindRunnables.clear();                                                          
1321             }                                                                                            
1322             for (final Runnable r : deferredBindRunnables) {                                             
1323                 mHandler.post(r);                                                                        
1324             }                                                                                            
1325         }                                                                                                
1326         // Run all the bind complete runnables after workspace is bound.                                 
1327         if (!mBindCompleteRunnables.isEmpty()) {                                                         
1328             synchronized(mBindCompleteRunnables) {                                                       
1329                 for (final Runnable r : mBindCompleteRunnables) {                                        
1330                     runOnWorkerThread(r);                                                                
1331                 }                                                                                        
1332                 mBindCompleteRunnables.clear();                                                          
1333             }                                                                                            
1334         }                                                                                                
1335     }                                                                                                    
1336                                                                                                          
1337     public void stopLoader() {                                                                           
1338         synchronized (mLock) {                                                                           
1339             if (mLoaderTask != null) {                                                                   
1340                 mLoaderTask.stopLocked();                                                                
1341             }                                                                                            
1342         }                                                                                                
1343     }                                                                                                    
1344                                                                                                          
1345     /**                                                                                                  
1346      * Loads the workspace screen ids in an ordered list.                                                
1347      */                                                                                                  
1348     @Thunk                                                                                               
1349     static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                                     
1350         final ContentResolver contentResolver = context.getContentResolver();                            
1351         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1352         // Get screens ordered by rank.                                                                  
1353         final Cursor sc = contentResolver.query(screensUri, null, null, null, LauncherSettings.WorkspaceS🔵
1354         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1355         try {                                                                                            
1356             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1357             while (sc.moveToNext()) {                                                                    
1358                 try {                                                                                    
1359                     screenIds.add(sc.getLong(idIndex));                                                  
1360                 } catch (java.lang.Exception e) {                                                        
1361                     Launcher.addDumpLog(TAG, ("Desktop items loading interrupted" + " - invalid screens: 🔵
1362                 }                                                                                        
1363             }                                                                                            
1364         } finally {                                                                                      
1365             sc.close();                                                                                  
1366         }                                                                                                
1367         return screenIds;                                                                                
1368     }                                                                                                    
1369                                                                                                          
1370     public boolean isAllAppsLoaded() {                                                                   
1371         return mAllAppsLoaded;                                                                           
1372     }                                                                                                    
1373                                                                                                          
1374     boolean isLoadingWorkspace() {                                                                       
1375         synchronized (mLock) {                                                                           
1376             if (mLoaderTask != null) {                                                                   
1377                 return mLoaderTask.isLoadingWorkspace();                                                 
1378             }                                                                                            
1379         }                                                                                                
1380         return false;                                                                                    
1381     }                                                                                                    
1382                                                                                                          
1383     /**                                                                                                  
1384      * Runnable for the thread that loads the contents of the launcher:                                  
1385      *   - workspace icons                                                                               
1386      *   - widgets                                                                                       
1387      *   - all apps icons                                                                                
1388      */                                                                                                  
1389     private class LoaderTask implements Runnable {                                                       
1390         private Context mContext;                                                                        
1391                                                                                                          
1392         @Thunk                                                                                           
1393         boolean mIsLoadingAndBindingWorkspace;                                                           
1394                                                                                                          
1395         private boolean mStopped;                                                                        
1396                                                                                                          
1397         @Thunk                                                                                           
1398         boolean mLoadAndBindStepFinished;                                                                
1399                                                                                                          
1400         private int mFlags;                                                                              
1401                                                                                                          
1402         LoaderTask(Context context, int flags) {                                                         
1403             mContext = context;                                                                          
1404             mFlags = flags;                                                                              
1405         }                                                                                                
1406                                                                                                          
1407         boolean isLoadingWorkspace() {                                                                   
1408             return mIsLoadingAndBindingWorkspace;                                                        
1409         }                                                                                                
1410                                                                                                          
1411         private void loadAndBindWorkspace() {                                                            
1412             mIsLoadingAndBindingWorkspace = true;                                                        
1413             // Load the workspace                                                                        
1414             if (DEBUG_LOADERS) {                                                                         
1415                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1416             }                                                                                            
1417             if (!mWorkspaceLoaded) {                                                                     
1418                 loadWorkspace();                                                                         
1419                 synchronized(this) {                                                                     
1420                     if (mStopped) {                                                                      
1421                         return;                                                                          
1422                     }                                                                                    
1423                     mWorkspaceLoaded = true;                                                             
1424                 }                                                                                        
1425             }                                                                                            
1426             // Bind the workspace                                                                        
1427             bindWorkspace(-1);                                                                           
1428         }                                                                                                
1429                                                                                                          
1430         private void waitForIdle() {                                                                     
1431             // Wait until the either we're stopped or the other threads are done.                        
1432             // This way we don't start loading all apps until the workspace has settled                  
1433             // down.                                                                                     
1434             synchronized (LoaderTask.this) {                                                             
1435                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1436                                                                                                          
1437                 mHandler.postIdle(new Runnable() {                                                       
1438                         public void run() {                                                              
1439                             synchronized (LoaderTask.this) {                                             
1440                                 mLoadAndBindStepFinished = true;                                         
1441                                 if (DEBUG_LOADERS) {                                                     
1442                                     Log.d(TAG, "done with previous binding step");                       
1443                                 }                                                                        
1444                                 LoaderTask.this.notify();                                                
1445                             }                                                                            
1446                         }                                                                                
1447                     });                                                                                  
1448                                                                                                          
1449                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1450                     try {                                                                                
1451                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1452                         // wait no longer than 1sec at a time                                            
1453                         this.wait(1000);                                                                 
1454                     } catch (InterruptedException ex) {                                                  
1455                         // Ignore                                                                        
1456                     }                                                                                    
1457                 }                                                                                        
1458                 if (DEBUG_LOADERS) {                                                                     
1459                     Log.d(TAG, "waited "                                                                 
1460                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1461                             + "ms for previous step to finish binding");                                 
1462                 }                                                                                        
1463             }                                                                                            
1464         }                                                                                                
1465                                                                                                          
1466         void runBindSynchronousPage(int synchronousBindPage) {                                           
1467             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1468                 // Ensure that we have a valid page index to load synchronously                          
1469                 throw new RuntimeException("Should not call runBindSynchronousPage() without " + "valid p🔵
1470             }                                                                                            
1471             if ((!mAllAppsLoaded) || (!mWorkspaceLoaded)) {                                              
1472                 // Ensure that we don't try and bind a specified page when the pages have not been       
1473                 // loaded already (we should load everything asynchronously in that case)                
1474                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1475             }                                                                                            
1476             synchronized(mLock) {                                                                        
1477                 if (mIsLoaderTaskRunning) {                                                              
1478                     // Ensure that we are never running the background loading at this point since       
1479                     // we also touch the background collections                                          
1480                     throw new RuntimeException("Error! Background loading is already running");          
1481                 }                                                                                        
1482             }                                                                                            
1483             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1484             // data structures, we can't allow any other thread to touch that data, but because          
1485             // this call is synchronous, we can get away with not locking).                              
1486             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1487             // operations from the previous activity.  We need to ensure that all queued operations      
1488             // are executed before any synchronous binding work is done.                                 
1489             mHandler.flush();                                                                            
1490             // Divide the set of loaded items into those that we are binding synchronously, and          
1491             // everything else that is to be bound normally (asynchronously).                            
1492             bindWorkspace(synchronousBindPage);                                                          
1493             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1494             // arise from that.                                                                          
1495             onlyBindAllApps();                                                                           
1496         }                                                                                                
1497                                                                                                          
1498         public void run() {                                                                              
1499             synchronized(mLock) {                                                                        
1500                 if (mStopped) {                                                                          
1501                     return;                                                                              
1502                 }                                                                                        
1503                 mIsLoaderTaskRunning = true;                                                             
1504             }                                                                                            
1505             // Optimize for end-user experience: if the Launcher is up and // running with the           
1506             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1507             // workspace first (default).                                                                
1508             keep_running : {                                                                             
1509                 if (DEBUG_LOADERS) {                                                                     
1510                     Log.d(TAG, "step 1: loading workspace");                                             
1511                 }                                                                                        
1512                 loadAndBindWorkspace();                                                                  
1513                 if (mStopped) {                                                                          
1514                     break keep_running;                                                                  
1515                 }                                                                                        
1516                 waitForIdle();                                                                           
1517                 // second step                                                                           
1518                 if (DEBUG_LOADERS) {                                                                     
1519                     Log.d(TAG, "step 2: loading all apps");                                              
1520                 }                                                                                        
1521                 loadAndBindAllApps();                                                                    
1522             }                                                                                            
1523             // Clear out this reference, otherwise we end up holding it until all of the                 
1524             // callback runnables are done.                                                              
1525             mContext = null;                                                                             
1526             synchronized(mLock) {                                                                        
1527                 // If we are still the last one to be scheduled, remove ourselves.                       
1528                 if (mLoaderTask == this) {                                                               
1529                     mLoaderTask = null;                                                                  
1530                 }                                                                                        
1531                 mIsLoaderTaskRunning = false;                                                            
1532                 mHasLoaderCompletedOnce = true;                                                          
1533             }                                                                                            
1534         }                                                                                                
1535                                                                                                          
1536         public void stopLocked() {                                                                       
1537             synchronized (LoaderTask.this) {                                                             
1538                 mStopped = true;                                                                         
1539                 this.notify();                                                                           
1540             }                                                                                            
1541         }                                                                                                
1542                                                                                                          
1543         /**                                                                                              
1544          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1545          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1546          * object that was around when the deferred message was scheduled, and if there's                
1547          * a new Callbacks object around then also return null.  This will save us from                  
1548          * calling onto it with data that will be ignored.                                               
1549          */                                                                                              
1550         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1551             synchronized (mLock) {                                                                       
1552                 if (mStopped) {                                                                          
1553                     return null;                                                                         
1554                 }                                                                                        
1555                                                                                                          
1556                 if (mCallbacks == null) {                                                                
1557                     return null;                                                                         
1558                 }                                                                                        
1559                                                                                                          
1560                 final Callbacks callbacks = mCallbacks.get();                                            
1561                 if (callbacks != oldCallbacks) {                                                         
1562                     return null;                                                                         
1563                 }                                                                                        
1564                 if (callbacks == null) {                                                                 
1565                     Log.w(TAG, "no mCallbacks");                                                         
1566                     return null;                                                                         
1567                 }                                                                                        
1568                                                                                                          
1569                 return callbacks;                                                                        
1570             }                                                                                            
1571         }                                                                                                
1572                                                                                                          
1573         // check & update map of what's occupied; used to discard overlapping/invalid items              
1574         private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {         
1575             LauncherAppState app = LauncherAppState.getInstance();                                       
1576             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1577             final int countX = ((int) (profile.numColumns));                                             
1578             final int countY = ((int) (profile.numRows));                                                
1579             long containerIndex = item.screenId;                                                         
1580             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1581                 // Return early if we detect that an item is under the hotseat button                    
1582                 if ((mCallbacks == null) || mCallbacks.get().isAllAppsButtonRank(((int) (item.screenId)))🔵
1583                     Log.e(TAG, ((((((("Error loading shortcut into hotseat " + item) + " into position ("🔵
1584                     return false;                                                                        
1585                 }                                                                                        
1586                 final ItemInfo[][] hotseatItems = occupied.get(((long) (LauncherSettings.Favorites.CONTAI🔵
1587                 if (item.screenId >= profile.numHotseatIcons) {                                          
1588                     Log.e(TAG, ((((("Error loading shortcut " + item) + " into hotseat position ") + item🔵
1589                     return false;                                                                        
1590                 }                                                                                        
1591                 if (hotseatItems != null) {                                                              
1592                     if (hotseatItems[((int) (item.screenId))][0] != null) {                              
1593                         Log.e(TAG, (((((((("Error loading shortcut into hotseat " + item) + " into positi🔵
1594                         return false;                                                                    
1595                     } else {                                                                             
1596                         hotseatItems[((int) (item.screenId))][0] = item;                                 
1597                         return true;                                                                     
1598                     }                                                                                    
1599                 } else {                                                                                 
1600                     final ItemInfo[][] items = new ItemInfo[((int) (profile.numHotseatIcons))][1];       
1601                     items[((int) (item.screenId))][0] = item;                                            
1602                     occupied.put(((long) (LauncherSettings.Favorites.CONTAINER_HOTSEAT)), items);        
1603                     return true;                                                                         
1604                 }                                                                                        
1605             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1606                 // Skip further checking if it is not the hotseat or workspace container                 
1607                 return true;                                                                             
1608             }                                                                                            
1609             if (!occupied.containsKey(item.screenId)) {                                                  
1610                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1611                 occupied.put(item.screenId, items);                                                      
1612             }                                                                                            
1613             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1614             if (((((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && (item.cellX < 0)) 🔵
1615                 Log.e(TAG, ((((((((((((("Error loading shortcut " + item) + " into cell (") + containerIn🔵
1616                 return false;                                                                            
1617             }                                                                                            
1618             // Check if any workspace icons overlap with each other                                      
1619             for (int x = item.cellX; x < (item.cellX + item.spanX); x++) {                               
1620                 for (int y = item.cellY; y < (item.cellY + item.spanY); y++) {                           
1621                     if (screens[x][y] != null) {                                                         
1622                         Log.e(TAG, (((((((((("Error loading shortcut " + item) + " into cell (") + contai🔵
1623                         return false;                                                                    
1624                     }                                                                                    
1625                 }                                                                                        
1626             }                                                                                            
1627             for (int x = item.cellX; x < (item.cellX + item.spanX); x++) {                               
1628                 for (int y = item.cellY; y < (item.cellY + item.spanY); y++) {                           
1629                     screens[x][y] = item;                                                                
1630                 }                                                                                        
1631             }                                                                                            
1632             return true;                                                                                 
1633         }                                                                                                
1634                                                                                                          
1635         /** Clears all the sBg data structures */                                                        
1636         private void clearSBgDataStructures() {                                                          
1637             synchronized(sBgLock) {                                                                      
1638                 sBgWorkspaceItems.clear();                                                               
1639                 sBgAppWidgets.clear();                                                                   
1640                 sBgFolders.clear();                                                                      
1641                 sBgItemsIdMap.clear();                                                                   
1642                 sBgWorkspaceScreens.clear();                                                             
1643             }                                                                                            
1644         }                                                                                                
1645                                                                                                          
1646         private void loadWorkspace() {                                                                   
1647             final long t = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                             
1648             final Context context = mContext;                                                            
1649             final ContentResolver contentResolver = context.getContentResolver();                        
1650             final PackageManager manager = context.getPackageManager();                                  
1651             final boolean isSafeMode = manager.isSafeMode();                                             
1652             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1653             final boolean isSdCardReady = context.registerReceiver(null, new IntentFilter(StartupReceiver🔵
1654             LauncherAppState app = LauncherAppState.getInstance();                                       
1655             InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                            
1656             int countX = ((int) (profile.numColumns));                                                   
1657             int countY = ((int) (profile.numRows));                                                      
1658             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1659                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1660                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1661             }                                                                                            
1662             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1663                 // append the user's Launcher2 shortcuts                                                 
1664                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1665                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1666             } else {                                                                                     
1667                 // Make sure the default workspace is loaded                                             
1668                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1669                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1670             }                                                                                            
1671             synchronized(sBgLock) {                                                                      
1672                 clearSBgDataStructures();                                                                
1673                 final HashMap<String, Integer> installingPkgs = PackageInstallerCompat.getInstance(mConte🔵
1674                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1675                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1676                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
1677                 if (DEBUG_LOADERS) {                                                                     
1678                     Log.d(TAG, "loading model from " + contentUri);                                      
1679                 }                                                                                        
1680                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1681                 // +1 for the hotseat (it can be larger than the workspace)                              
1682                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1683                 // before any earlier duplicates)                                                        
1684                 final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();                        
1685                 try {                                                                                    
1686                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1687                     final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);  
1688                     final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);    
1689                     final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAIN🔵
1690                     final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYP🔵
1691                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWI🔵
1692                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites🔵
1693                     final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);  
1694                     final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);    
1695                     final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);    
1696                     final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);    
1697                     final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);    
1698                     final int rankIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RANK);      
1699                     final int restoredIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED🔵
1700                     final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE🔵
1701                     final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);
1702                     final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);                         
1703                     final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();          
1704                     for (UserHandleCompat user : mUserManager.getUserProfiles()) {                       
1705                         allUsers.put(mUserManager.getSerialNumberForUser(user), user);                   
1706                     }                                                                                    
1707                     ShortcutInfo info;                                                                   
1708                     String intentDescription;                                                            
1709                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1710                     int container;                                                                       
1711                     long id;                                                                             
1712                     long serialNumber;                                                                   
1713                     Intent intent;                                                                       
1714                     UserHandleCompat user;                                                               
1715                     while ((!mStopped) && c.moveToNext()) {                                              
1716                         try {                                                                            
1717                             int itemType = c.getInt(itemTypeIndex);                                      
1718                             boolean restored = 0 != c.getInt(restoredIndex);                             
1719                             boolean allowMissingTarget = false;                                          
1720                             container = c.getInt(containerIndex);                                        
1721                             switch (itemType) {                                                          
1722                                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                  
1723                                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                     
1724                                     id = c.getLong(idIndex);                                             
1725                                     intentDescription = c.getString(intentIndex);                        
1726                                     serialNumber = c.getInt(profileIdIndex);                             
1727                                     user = allUsers.get(serialNumber);                                   
1728                                     int promiseType = c.getInt(restoredIndex);                           
1729                                     int disabledState = 0;                                               
1730                                     boolean itemReplaced = false;                                        
1731                                     if (user == null) {                                                  
1732                                         // User has been deleted remove the item.                        
1733                                         itemsToRemove.add(id);                                           
1734                                         continue;                                                        
1735                                     }                                                                    
1736                                     try {                                                                
1737                                         intent = Intent.parseUri(intentDescription, 0);                  
1738                                         ComponentName cn = intent.getComponent();                        
1739                                         if ((cn != null) && (cn.getPackageName() != null)) {             
1740                                             boolean validPkg = launcherApps.isPackageEnabledForProfile(cn🔵
1741                                             boolean validComponent = validPkg && launcherApps.isActivityE🔵
1742                                             if (validComponent) {                                        
1743                                                 if (restored) {                                          
1744                                                     // no special handling necessary for this item       
1745                                                     restoredRows.add(id);                                
1746                                                     restored = false;                                    
1747                                                 }                                                        
1748                                             } else if (validPkg) {                                       
1749                                                 intent = null;                                           
1750                                                 if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 🔵
1751                                                     // We allow auto install apps to have their intent   
1752                                                     // updated after an install.                         
1753                                                     intent = manager.getLaunchIntentForPackage(cn.getPack🔵
1754                                                     if (intent != null) {                                
1755                                                         ContentValues values = new ContentValues();      
1756                                                         values.put(LauncherSettings.Favorites.INTENT, int🔵
1757                                                         updateItem(id, values);                          
1758                                                     }                                                    
1759                                                 }                                                        
1760                                                 if (intent == null) {                                    
1761                                                     // The app is installed but the component is no      
1762                                                     // longer available.                                 
1763                                                     Launcher.addDumpLog(TAG, "Invalid component removed: 🔵
1764                                                     itemsToRemove.add(id);                               
1765                                                     continue;                                            
1766                                                 } else {                                                 
1767                                                     // no special handling necessary for this item       
1768                                                     restoredRows.add(id);                                
1769                                                     restored = false;                                    
1770                                                 }                                                        
1771                                             } else if (restored) {                                       
1772                                                 // Package is not yet available but might be             
1773                                                 // installed later.                                      
1774                                                 Launcher.addDumpLog(TAG, "package not yet restored: " + c🔵
1775                                                 if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 🔵
1776                                                     // Restore has started once.                         
1777                                                 } else if (installingPkgs.containsKey(cn.getPackageName()🔵
1778                                                     // App restore has started. Update the flag          
1779                                                     promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;    
1780                                                     ContentValues values = new ContentValues();          
1781                                                     values.put(LauncherSettings.Favorites.RESTORED, promi🔵
1782                                                     updateItem(id, values);                              
1783                                                 } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_🔵
1784                                                 // This is a common app. Try to replace this.            
1785                                                     int appType = CommonAppTypeParser.decodeItemTypeFromF🔵
1786                                                     CommonAppTypeParser parser = new CommonAppTypeParser(🔵
1787                                                     if (parser.findDefaultApp()) {                       
1788                                                         // Default app found. Replace it.                
1789                                                         intent = parser.parsedIntent;                    
1790                                                         cn = intent.getComponent();                      
1791                                                         ContentValues values = parser.parsedValues;      
1792                                                         values.put(LauncherSettings.Favorites.RESTORED, 0🔵
1793                                                         updateItem(id, values);                          
1794                                                         restored = false;                                
1795                                                         itemReplaced = true;                             
1796                                                     } else if (REMOVE_UNRESTORED_ICONS) {                
1797                                                         Launcher.addDumpLog(TAG, "Unrestored package remo🔵
1798                                                         itemsToRemove.add(id);                           
1799                                                         continue;                                        
1800                                                     }                                                    
1801                                                 } else if (REMOVE_UNRESTORED_ICONS) {                    
1802                                                     Launcher.addDumpLog(TAG, "Unrestored package removed:🔵
1803                                                     itemsToRemove.add(id);                               
1804                                                     continue;                                            
1805                                                 }                                                        
1806                                             } else if (launcherApps.isAppEnabled(manager, cn.getPackageNa🔵
1807                                                 // Package is present but not available.                 
1808                                                 allowMissingTarget = true;                               
1809                                                 disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
1810                                             } else if (!isSdCardReady) {                                 
1811                                                 // SdCard is not ready yet. Package might get available, 
1812                                                 // once it is ready.                                     
1813                                                 Launcher.addDumpLog(TAG, ("Invalid package: " + cn) + " (🔵
1814                                                 HashSet<String> pkgs = sPendingPackages.get(user);       
1815                                                 if (pkgs == null) {                                      
1816                                                     pkgs = new HashSet<String>();                        
1817                                                     sPendingPackages.put(user, pkgs);                    
1818                                                 }                                                        
1819                                                 pkgs.add(cn.getPackageName());                           
1820                                                 allowMissingTarget = true;                               
1821                                                 // Add the icon on the workspace anyway.                 
1822                                             } else {                                                     
1823                                                 // Do not wait for external media load anymore.          
1824                                                 // Log the invalid package, and remove it                
1825                                                 Launcher.addDumpLog(TAG, "Invalid package removed: " + cn🔵
1826                                                 itemsToRemove.add(id);                                   
1827                                                 continue;                                                
1828                                             }                                                            
1829                                         } else if (cn == null) {                                         
1830                                             // For shortcuts with no component, keep them as they are    
1831                                             restoredRows.add(id);                                        
1832                                             restored = false;                                            
1833                                         }                                                                
1834                                     } catch (URISyntaxException e) {                                     
1835                                         Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, tru🔵
1836                                         continue;                                                        
1837                                     }                                                                    
1838                                     boolean useLowResIcon = (container >= 0) && (c.getInt(rankIndex) >= F🔵
1839                                     if (itemReplaced) {                                                  
1840                                         if (user.equals(UserHandleCompat.myUserHandle())) {              
1841                                             info = getAppShortcutInfo(manager, intent, user, context, nul🔵
1842                                         } else {                                                         
1843                                             // Don't replace items for other profiles.                   
1844                                             itemsToRemove.add(id);                                       
1845                                             continue;                                                    
1846                                         }                                                                
1847                                     } else if (restored) {                                               
1848                                         if (user.equals(UserHandleCompat.myUserHandle())) {              
1849                                             Launcher.addDumpLog(TAG, "constructing info for partially res🔵
1850                                             info = getRestoredItemInfo(c, titleIndex, intent, promiseType🔵
1851                                             intent = getRestoredItemIntent(c, context, intent);          
1852                                         } else {                                                         
1853                                             // Don't restore items for other profiles.                   
1854                                             itemsToRemove.add(id);                                       
1855                                             continue;                                                    
1856                                         }                                                                
1857                                     } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATI🔵
1858                                         info = getAppShortcutInfo(manager, intent, user, context, c, curs🔵
1859                                     } else {                                                             
1860                                         info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);  
1861                                         // App shortcuts that used to be automatically added to Launcher 
1862                                         // didn't always have the correct intent flags set, so do that   
1863                                         // here                                                          
1864                                         if ((((intent.getAction() != null) && (intent.getCategories() != 🔵
1865                                             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_A🔵
1866                                         }                                                                
1867                                     }                                                                    
1868                                     if (info != null) {                                                  
1869                                         info.id = id;                                                    
1870                                         info.intent = intent;                                            
1871                                         info.container = container;                                      
1872                                         info.screenId = c.getInt(screenIndex);                           
1873                                         info.cellX = c.getInt(cellXIndex);                               
1874                                         info.cellY = c.getInt(cellYIndex);                               
1875                                         info.rank = c.getInt(rankIndex);                                 
1876                                         info.spanX = 1;                                                  
1877                                         info.spanY = 1;                                                  
1878                                         info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);      
1879                                         if (info.promisedIntent != null) {                               
1880                                             info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNu🔵
1881                                         }                                                                
1882                                         info.isDisabled = disabledState;                                 
1883                                         if (isSafeMode && (!Utilities.isSystemApp(context, intent))) {   
1884                                             info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;      
1885                                         }                                                                
1886                                     // check & update map of what's occupied                             
1887                                         if (!checkItemPlacement(occupied, info)) {                       
1888                                             itemsToRemove.add(id);                                       
1889                                             break;                                                       
1890                                         }                                                                
1891                                         if (restored) {                                                  
1892                                             ComponentName cn = info.getTargetComponent();                
1893                                             if (cn != null) {                                            
1894                                                 Integer progress = installingPkgs.get(cn.getPackageName()🔵
1895                                                 if (progress != null) {                                  
1896                                                     info.setInstallProgress(progress);                   
1897                                                 } else {                                                 
1898                                                     info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACT🔵
1899                                                 }                                                        
1900                                             }                                                            
1901                                         }                                                                
1902                                         switch (container) {                                             
1903                                             case LauncherSettings.Favorites.CONTAINER_DESKTOP :          
1904                                             case LauncherSettings.Favorites.CONTAINER_HOTSEAT :          
1905                                                 sBgWorkspaceItems.add(info);                             
1906                                                 break;                                                   
1907                                             default :                                                    
1908                                         // Item is in a user folder                                      
1909                                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, cont🔵
1910                                                 folderInfo.add(info);                                    
1911                                                 break;                                                   
1912                                         }                                                                
1913                                         sBgItemsIdMap.put(info.id, info);                                
1914                                     } else {                                                             
1915                                         throw new RuntimeException("Unexpected null ShortcutInfo");      
1916                                     }                                                                    
1917                                     break;                                                               
1918                                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                       
1919                                     id = c.getLong(idIndex);                                             
1920                                     FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);            
1921                                 // Do not trim the folder label, as is was set by the user.              
1922                                     folderInfo.title = c.getString(titleIndex);                          
1923                                     folderInfo.id = id;                                                  
1924                                     folderInfo.container = container;                                    
1925                                     folderInfo.screenId = c.getInt(screenIndex);                         
1926                                     folderInfo.cellX = c.getInt(cellXIndex);                             
1927                                     folderInfo.cellY = c.getInt(cellYIndex);                             
1928                                     folderInfo.spanX = 1;                                                
1929                                     folderInfo.spanY = 1;                                                
1930                                     folderInfo.options = c.getInt(optionsIndex);                         
1931                                 // check & update map of what's occupied                                 
1932                                     if (!checkItemPlacement(occupied, folderInfo)) {                     
1933                                         itemsToRemove.add(id);                                           
1934                                         break;                                                           
1935                                     }                                                                    
1936                                     switch (container) {                                                 
1937                                         case LauncherSettings.Favorites.CONTAINER_DESKTOP :              
1938                                         case LauncherSettings.Favorites.CONTAINER_HOTSEAT :              
1939                                             sBgWorkspaceItems.add(folderInfo);                           
1940                                             break;                                                       
1941                                     }                                                                    
1942                                     if (restored) {                                                      
1943                                         // no special handling required for restored folders             
1944                                         restoredRows.add(id);                                            
1945                                     }                                                                    
1946                                     sBgItemsIdMap.put(folderInfo.id, folderInfo);                        
1947                                     sBgFolders.put(folderInfo.id, folderInfo);                           
1948                                     break;                                                               
1949                                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                    
1950                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
1951                                 // Read all Launcher-specific widget details                             
1952                                 boolean customWidget = itemType ==                                       
1953                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
1954                                                                                                          
1955                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
1956                                                                                                          
1957 <<<<<<< LEFT                                                                                             
1958                                 serialNumber = c.getLong(profileIdIndex);                                
1959                                                                                                          
1960 ||||||| BASE                                                                                             
1961 /*d94z9sk0k4hf9j3ijd - note the base isn't actually empty, spork simply doesn't generate a base - gd930kw🔵
1962 =======                                                                                                  
1963                                                                                                          
1964                                 serialNumber= c.getLong(profileIdIndex);                                 
1965                                 user = mUserManager.getUserForSerialNumber(serialNumber);                
1966                                 if (user == null) {                                                      
1967                                     // User has been deleted remove the item.                            
1968                                     itemsToRemove.add(id);                                               
1969                                     continue;                                                            
1970                                 }                                                                        
1971                                                                                                          
1972 >>>>>>> RIGHT                                                                                            
1973                                 String savedProvider = c.getString(appWidgetProviderIndex);              
1974                                 id = c.getLong(idIndex);                                                 
1975                                 user = allUsers.get(serialNumber);                                       
1976                                 if (user == null) {                                                      
1977                                     itemsToRemove.add(id);                                               
1978                                     continue;                                                            
1979                                 }                                                                        
1980                                                                                                          
1981                                 final ComponentName component =                                          
1982                                         ComponentName.unflattenFromString(savedProvider);                
1983                                                                                                          
1984                                 final int restoreStatus = c.getInt(restoredIndex);                       
1985                                 final boolean isIdValid = (restoreStatus &                               
1986                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                   
1987                                 final boolean wasProviderReady = (restoreStatus &                        
1988                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;             
1989                                                                                                          
1990                                 final LauncherAppWidgetProviderInfo provider =                           
1991                                         LauncherModel.getProviderInfo(context,                           
1992                                                 ComponentName.unflattenFromString(savedProvider),        
1993                                                 user);                                                   
1994                                                                                                          
1995                                 final boolean isProviderReady = isValidProvider(provider);               
1996                                 if (!isSafeMode && !customWidget &&                                      
1997                                         wasProviderReady && !isProviderReady) {                          
1998                                     String log = "Deleting widget that isn't installed anymore: "        
1999                                             + "id=" + id + " appWidgetId=" + appWidgetId;                
2000                                                                                                          
2001                                     Log.e(TAG, log);                                                     
2002                                     Launcher.addDumpLog(TAG, log, false);                                
2003                                     itemsToRemove.add(id);                                               
2004                                 } else {                                                                 
2005                                     if (isProviderReady) {                                               
2006                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2007                                                 provider.provider);                                      
2008                                                                                                          
2009                                         int status = restoreStatus;                                      
2010                                         if (!wasProviderReady) {                                         
2011                                             // If provider was not previously ready, update the          
2012                                             // status and UI flag.                                       
2013                                                                                                          
2014                                             // Id would be valid only if the widget restore broadcast was🔵
2015                                             if (isIdValid) {                                             
2016                                                 status = LauncherAppWidgetInfo.RESTORE_COMPLETED;        
2017                                             } else {                                                     
2018                                                 status &= ~LauncherAppWidgetInfo                         
2019                                                         .FLAG_PROVIDER_NOT_READY;                        
2020                                             }                                                            
2021                                         }                                                                
2022                                         appWidgetInfo.restoreStatus = status;                            
2023                                     } else {                                                             
2024                                         Log.v(TAG, "Widget restore pending id=" + id                     
2025                                                 + " appWidgetId=" + appWidgetId                          
2026                                                 + " status =" + restoreStatus);                          
2027                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2028                                                 component);                                              
2029                                         appWidgetInfo.restoreStatus = restoreStatus;                     
2030                                         Integer installProgress = installingPkgs.get(component.getPackage🔵
2031                                                                                                          
2032                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) 🔵
2033                                             // Restore has started once.                                 
2034                                         } else if (installProgress != null) {                            
2035                                             // App restore has started. Update the flag                  
2036                                             appWidgetInfo.restoreStatus |=                               
2037                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;          
2038                                         } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {             
2039                                             Launcher.addDumpLog(TAG,                                     
2040                                                     "Unrestored widget removed: " + component, true);    
2041                                             itemsToRemove.add(id);                                       
2042                                             continue;                                                    
2043                                         }                                                                
2044                                                                                                          
2045                                         appWidgetInfo.installProgress =                                  
2046                                                 installProgress == null ? 0 : installProgress;           
2047                                     }                                                                    
2048                                                                                                          
2049                                     appWidgetInfo.id = id;                                               
2050                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2051                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2052                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2053                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2054                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2055                                     appWidgetInfo.user = user;                                           
2056                                                                                                          
2057                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2058                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2059                                         Log.e(TAG, "Widget found where container != " +                  
2060                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2061                                         continue;                                                        
2062                                     }                                                                    
2063                                                                                                          
2064                                     appWidgetInfo.container = container;                                 
2065                                     // check & update map of what's occupied                             
2066                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {                  
2067                                         itemsToRemove.add(id);                                           
2068                                         break;                                                           
2069                                     }                                                                    
2070                                                                                                          
2071                                     if (!customWidget) {                                                 
2072                                         String providerName =                                            
2073                                                 appWidgetInfo.providerName.flattenToString();            
2074                                         if (!providerName.equals(savedProvider) ||                       
2075                                                 (appWidgetInfo.restoreStatus != restoreStatus)) {        
2076                                             ContentValues values = new ContentValues();                  
2077                                             values.put(                                                  
2078                                                     LauncherSettings.Favorites.APPWIDGET_PROVIDER,       
2079                                                     providerName);                                       
2080                                             values.put(LauncherSettings.Favorites.RESTORED,              
2081                                                     appWidgetInfo.restoreStatus);                        
2082                                             updateItem(id, values);                                      
2083                                         }                                                                
2084                                     }                                                                    
2085                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2086                                     sBgAppWidgets.add(appWidgetInfo);                                    
2087                                 }                                                                        
2088                                 break;                                                                   
2089                             }                                                                            
2090                         } catch (java.lang.Exception e) {                                                
2091                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2092                         }                                                                                
2093                     }                                                                                    
2094                 } finally {                                                                              
2095                     if (c != null) {                                                                     
2096                         c.close();                                                                       
2097                     }                                                                                    
2098                 }                                                                                        
2099                 // Break early if we've stopped loading                                                  
2100                 if (mStopped) {                                                                          
2101                     clearSBgDataStructures();                                                            
2102                     return;                                                                              
2103                 }                                                                                        
2104                 if (itemsToRemove.size() > 0) {                                                          
2105                     // Remove dead items                                                                 
2106                     contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI, Utilities.createDbSele🔵
2107                     if (DEBUG_LOADERS) {                                                                 
2108                         Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(LauncherSettings.Favor🔵
2109                     }                                                                                    
2110                     // Remove any empty folder                                                           
2111                     for (long folderId : LauncherAppState.getLauncherProvider().deleteEmptyFolders()) {  
2112                         sBgWorkspaceItems.remove(sBgFolders.get(folderId));                              
2113                         sBgFolders.remove(folderId);                                                     
2114                         sBgItemsIdMap.remove(folderId);                                                  
2115                     }                                                                                    
2116                 }                                                                                        
2117                 if (restoredRows.size() > 0) {                                                           
2118                     // Update restored items that no longer require special handling                     
2119                     ContentValues values = new ContentValues();                                          
2120                     values.put(LauncherSettings.Favorites.RESTORED, 0);                                  
2121                     contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values, Utilities.crea🔵
2122                 }                                                                                        
2123                 if ((!isSdCardReady) && (!sPendingPackages.isEmpty())) {                                 
2124                     context.registerReceiver(new AppsAvailabilityCheck(), new IntentFilter(StartupReceive🔵
2125                 }                                                                                        
2126                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2127                 // Remove any empty screens                                                              
2128                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                
2129                 for (ItemInfo item : sBgItemsIdMap) {                                                    
2130                     long screenId = item.screenId;                                                       
2131                     if ((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && unusedScreens🔵
2132                         unusedScreens.remove(screenId);                                                  
2133                     }                                                                                    
2134                 }                                                                                        
2135                     // If there are any empty screens remove them, and update.                           
2136                 if (unusedScreens.size() != 0) {                                                         
2137                     sBgWorkspaceScreens.removeAll(unusedScreens);                                        
2138                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2139                 }                                                                                        
2140                 if (DEBUG_LOADERS) {                                                                     
2141                     Log.d(TAG, ("loaded workspace in " + (SystemClock.uptimeMillis() - t)) + "ms");      
2142                     Log.d(TAG, "workspace layout: ");                                                    
2143                     int nScreens = occupied.size();                                                      
2144                     for (int y = 0; y < countY; y++) {                                                   
2145                         String line = "";                                                                
2146                         for (int i = 0; i < nScreens; i++) {                                             
2147                             long screenId = occupied.keyAt(i);                                           
2148                             if (screenId > 0) {                                                          
2149                                 line += " | ";                                                           
2150                             }                                                                            
2151                             ItemInfo[][] screen = occupied.valueAt(i);                                   
2152                             for (int x = 0; x < countX; x++) {                                           
2153                                 if ((x < screen.length) && (y < screen[x].length)) {                     
2154                                     line += (screen[x][y] != null) ? "#" : ".";                          
2155                                 } else {                                                                 
2156                                     line += "!";                                                         
2157                                 }                                                                        
2158                             }                                                                            
2159                         }                                                                                
2160                         Log.d(TAG, ("[ " + line) + " ]");                                                
2161                     }                                                                                    
2162                 }                                                                                        
2163             }                                                                                            
2164         }                                                                                                
2165                                                                                                          
2166         /**                                                                                              
2167          * Partially updates the item without any notification. Must be called on the worker thread.     
2168          */                                                                                              
2169         private void updateItem(long itemId, ContentValues update) {                                     
2170             mContext.getContentResolver().update(LauncherSettings.Favorites.CONTENT_URI, update, BaseColu🔵
2171         }                                                                                                
2172                                                                                                          
2173         /** Filters the set of items who are directly or indirectly (via another container) on the       
2174          * specified screen. */                                                                          
2175         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2176                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2177                 ArrayList<ItemInfo> currentScreenItems,                                                  
2178                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2179             // Purge any null ItemInfos                                                                  
2180             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2181             while (iter.hasNext()) {                                                                     
2182                 ItemInfo i = iter.next();                                                                
2183                 if (i == null) {                                                                         
2184                     iter.remove();                                                                       
2185                 }                                                                                        
2186             }                                                                                            
2187                                                                                                          
2188             // Order the set of items by their containers first, this allows use to walk through the     
2189             // list sequentially, build up a list of containers that are in the specified screen,        
2190             // as well as all items in those containers.                                                 
2191             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2192             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2193                 @Override                                                                                
2194                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2195                     return (int) (lhs.container - rhs.container);                                        
2196                 }                                                                                        
2197             });                                                                                          
2198             for (ItemInfo info : allWorkspaceItems) {                                                    
2199                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2200                     if (info.screenId == currentScreenId) {                                              
2201                         currentScreenItems.add(info);                                                    
2202                         itemsOnScreen.add(info.id);                                                      
2203                     } else {                                                                             
2204                         otherScreenItems.add(info);                                                      
2205                     }                                                                                    
2206                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2207                     currentScreenItems.add(info);                                                        
2208                     itemsOnScreen.add(info.id);                                                          
2209                 } else {                                                                                 
2210                     if (itemsOnScreen.contains(info.container)) {                                        
2211                         currentScreenItems.add(info);                                                    
2212                         itemsOnScreen.add(info.id);                                                      
2213                     } else {                                                                             
2214                         otherScreenItems.add(info);                                                      
2215                     }                                                                                    
2216                 }                                                                                        
2217             }                                                                                            
2218         }                                                                                                
2219                                                                                                          
2220         /** Filters the set of widgets which are on the specified screen. */                             
2221         private void filterCurrentAppWidgets(long currentScreenId,                                       
2222                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2223                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2224                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2225                                                                                                          
2226             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2227                 if (widget == null) continue;                                                            
2228                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2229                         widget.screenId == currentScreenId) {                                            
2230                     currentScreenWidgets.add(widget);                                                    
2231                 } else {                                                                                 
2232                     otherScreenWidgets.add(widget);                                                      
2233                 }                                                                                        
2234             }                                                                                            
2235         }                                                                                                
2236                                                                                                          
2237         /** Filters the set of folders which are on the specified screen. */                             
2238         private void filterCurrentFolders(long currentScreenId, LongArrayMap<ItemInfo> itemsIdMap, LongAr🔵
2239             int total = folders.size();                                                                  
2240             for (int i = 0; i < total; i++) {                                                            
2241                 long id = folders.keyAt(i);                                                              
2242                 FolderInfo folder = folders.valueAt(i);                                                  
2243                 ItemInfo info = itemsIdMap.get(id);                                                      
2244                 if ((info == null) || (folder == null)) {                                                
2245                     continue;                                                                            
2246                 }                                                                                        
2247                 if ((info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && (info.screenId ==🔵
2248                     currentScreenFolders.put(id, folder);                                                
2249                 } else {                                                                                 
2250                     otherScreenFolders.put(id, folder);                                                  
2251                 }                                                                                        
2252             }                                                                                            
2253         }                                                                                                
2254                                                                                                          
2255         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2256          * right) */                                                                                     
2257         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2258             final LauncherAppState app = LauncherAppState.getInstance();                                 
2259             final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                      
2260             // XXX: review this                                                                          
2261             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2262                 @Override                                                                                
2263                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2264                     int cellCountX = ((int) (profile.numColumns));                                       
2265                     int cellCountY = ((int) (profile.numRows));                                          
2266                     int screenOffset = cellCountX * cellCountY;                                          
2267                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1);// +1 hotseat       
2268                                                                                                          
2269                     long lr = (((lhs.container * containerOffset) + (lhs.screenId * screenOffset)) + (lhs🔵
2270                     long rr = (((rhs.container * containerOffset) + (rhs.screenId * screenOffset)) + (rhs🔵
2271                     return ((int) (lr - rr));                                                            
2272                 }                                                                                        
2273             });                                                                                          
2274         }                                                                                                
2275                                                                                                          
2276         private void bindWorkspaceScreens(final Callbacks oldCallbacks, final ArrayList<Long> orderedScre🔵
2277             final Runnable r = new Runnable() {                                                          
2278                 @Override                                                                                
2279                 public void run() {                                                                      
2280                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2281                     if (callbacks != null) {                                                             
2282                         callbacks.bindScreens(orderedScreens);                                           
2283                     }                                                                                    
2284                 }                                                                                        
2285             };                                                                                           
2286             runOnMainThread(r);                                                                          
2287         }                                                                                                
2288                                                                                                          
2289         private void bindWorkspaceItems(final Callbacks oldCallbacks, final ArrayList<ItemInfo> workspace🔵
2290             final boolean postOnMainThread = deferredBindRunnables != null;                              
2291             // Bind the workspace items                                                                  
2292             int N = workspaceItems.size();                                                               
2293             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2294                 final int start = i;                                                                     
2295                 final int chunkSize = ((i + ITEMS_CHUNK) <= N) ? ITEMS_CHUNK : N - i;                    
2296                 final Runnable r = new Runnable() {                                                      
2297                     @Override                                                                            
2298                     public void run() {                                                                  
2299                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2300                         if (callbacks != null) {                                                         
2301                             callbacks.bindItems(workspaceItems, start, start + chunkSize, false);        
2302                         }                                                                                
2303                     }                                                                                    
2304                 };                                                                                       
2305                 if (postOnMainThread) {                                                                  
2306                     synchronized(deferredBindRunnables) {                                                
2307                         deferredBindRunnables.add(r);                                                    
2308                     }                                                                                    
2309                 } else {                                                                                 
2310                     runOnMainThread(r);                                                                  
2311                 }                                                                                        
2312             }                                                                                            
2313             // Bind the folders                                                                          
2314             if (!folders.isEmpty()) {                                                                    
2315                 final Runnable r = new Runnable() {                                                      
2316                     public void run() {                                                                  
2317                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2318                         if (callbacks != null) {                                                         
2319                             callbacks.bindFolders(folders);                                              
2320                         }                                                                                
2321                     }                                                                                    
2322                 };                                                                                       
2323                 if (postOnMainThread) {                                                                  
2324                     synchronized(deferredBindRunnables) {                                                
2325                         deferredBindRunnables.add(r);                                                    
2326                     }                                                                                    
2327                 } else {                                                                                 
2328                     runOnMainThread(r);                                                                  
2329                 }                                                                                        
2330             }                                                                                            
2331             // Bind the widgets, one at a time                                                           
2332             N = appWidgets.size();                                                                       
2333             for (int i = 0; i < N; i++) {                                                                
2334                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2335                 final Runnable r = new Runnable() {                                                      
2336                     public void run() {                                                                  
2337                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2338                         if (callbacks != null) {                                                         
2339                             callbacks.bindAppWidget(widget);                                             
2340                         }                                                                                
2341                     }                                                                                    
2342                 };                                                                                       
2343                 if (postOnMainThread) {                                                                  
2344                     deferredBindRunnables.add(r);                                                        
2345                 } else {                                                                                 
2346                     runOnMainThread(r);                                                                  
2347                 }                                                                                        
2348             }                                                                                            
2349         }                                                                                                
2350                                                                                                          
2351         /**                                                                                              
2352          * Binds all loaded data to actual views on the main thread.                                     
2353          */                                                                                              
2354         private void bindWorkspace(int synchronizeBindPage) {                                            
2355             final long t = SystemClock.uptimeMillis();                                                   
2356             Runnable r;                                                                                  
2357             // Don't use these two variables in any of the callback runnables.                           
2358             // Otherwise we hold a reference to them.                                                    
2359             final Callbacks oldCallbacks = mCallbacks.get();                                             
2360             if (oldCallbacks == null) {                                                                  
2361                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2362                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2363                 return;                                                                                  
2364             }                                                                                            
2365             // Save a copy of all the bg-thread collections                                              
2366             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2367             ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<LauncherAppWidgetInfo>();        
2368             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2369             final LongArrayMap<FolderInfo> folders;                                                      
2370             final LongArrayMap<ItemInfo> itemsIdMap;                                                     
2371             synchronized(sBgLock) {                                                                      
2372                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2373                 appWidgets.addAll(sBgAppWidgets);                                                        
2374                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2375                 folders = sBgFolders.clone();                                                            
2376                 itemsIdMap = sBgItemsIdMap.clone();                                                      
2377             }                                                                                            
2378             final boolean isLoadingSynchronously = synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;
2379             int currScreen = (isLoadingSynchronously) ? synchronizeBindPage : oldCallbacks.getCurrentWork🔵
2380             if (currScreen >= orderedScreenIds.size()) {                                                 
2381                 // There may be no workspace screens (just hotseat items and an empty page).             
2382                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2383             }                                                                                            
2384             final int currentScreen = currScreen;                                                        
2385             final long currentScreenId = (currentScreen < 0) ? INVALID_SCREEN_ID : orderedScreenIds.get(c🔵
2386             // Load all the items that are on the current page first (and in the process, unbind         
2387             // all the existing workspace items before we call startBinding() below.                     
2388             unbindWorkspaceItemsOnMainThread();                                                          
2389             // Separate the items that are on the current screen, and all the other remaining items      
2390             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2391             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2392             ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<LauncherAppWidgetInfo>(); 
2393             ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<LauncherAppWidgetInfo>();   
2394             LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();                              
2395             LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();                                
2396             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems, otherWork🔵
2397             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets, otherAppWidgets);    
2398             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders, otherFolders);    
2399             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2400             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2401             // Tell the workspace that we're about to start binding items                                
2402             r = new Runnable() {                                                                         
2403                 public void run() {                                                                      
2404                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2405                     if (callbacks != null) {                                                             
2406                         callbacks.startBinding();                                                        
2407                     }                                                                                    
2408                 }                                                                                        
2409             };                                                                                           
2410             runOnMainThread(r);                                                                          
2411             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2412             // Load items on the current page                                                            
2413             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets, currentFolders, nu🔵
2414             if (isLoadingSynchronously) {                                                                
2415                 r = new Runnable() {                                                                     
2416                     public void run() {                                                                  
2417                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2418                         if ((callbacks != null) && (currentScreen != PagedView.INVALID_RESTORE_PAGE)) {  
2419                             callbacks.onPageBoundSynchronously(currentScreen);                           
2420                         }                                                                                
2421                     }                                                                                    
2422                 };                                                                                       
2423                 runOnMainThread(r);                                                                      
2424             }                                                                                            
2425             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2426             // work until after the first render)                                                        
2427             synchronized(mDeferredBindRunnables) {                                                       
2428                 mDeferredBindRunnables.clear();                                                          
2429             }                                                                                            
2430             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders, isLoadin🔵
2431             // Tell the workspace that we're done binding items                                          
2432             r = new Runnable() {                                                                         
2433                 public void run() {                                                                      
2434                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2435                     if (callbacks != null) {                                                             
2436                         callbacks.finishBindingItems();                                                  
2437                     }                                                                                    
2438                     // If we're profiling, ensure this is the last thing in the queue.                   
2439                     if (DEBUG_LOADERS) {                                                                 
2440                         Log.d(TAG, ("bound workspace in " + (SystemClock.uptimeMillis() - t)) + "ms");   
2441                     }                                                                                    
2442                     mIsLoadingAndBindingWorkspace = false;                                               
2443                 }                                                                                        
2444             };                                                                                           
2445             if (isLoadingSynchronously) {                                                                
2446                 synchronized(mDeferredBindRunnables) {                                                   
2447                     mDeferredBindRunnables.add(r);                                                       
2448                 }                                                                                        
2449             } else {                                                                                     
2450                 runOnMainThread(r);                                                                      
2451             }                                                                                            
2452         }                                                                                                
2453                                                                                                          
2454         private void loadAndBindAllApps() {                                                              
2455             if (DEBUG_LOADERS) {                                                                         
2456                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2457             }                                                                                            
2458             if (!mAllAppsLoaded) {                                                                       
2459                 loadAllApps();                                                                           
2460                 synchronized(this) {                                                                     
2461                     if (mStopped) {                                                                      
2462                         return;                                                                          
2463                     }                                                                                    
2464                 }                                                                                        
2465                 updateIconCache();                                                                       
2466                 synchronized(this) {                                                                     
2467                     if (mStopped) {                                                                      
2468                         return;                                                                          
2469                     }                                                                                    
2470                     mAllAppsLoaded = true;                                                               
2471                 }                                                                                        
2472             } else {                                                                                     
2473                 onlyBindAllApps();                                                                       
2474             }                                                                                            
2475         }                                                                                                
2476                                                                                                          
2477         private void updateIconCache() {                                                                 
2478             // Ignore packages which have a promise icon.                                                
2479             HashSet<String> packagesToIgnore = new HashSet<>();                                          
2480             synchronized(sBgLock) {                                                                      
2481                 for (ItemInfo info : sBgItemsIdMap) {                                                    
2482                     if (info instanceof ShortcutInfo) {                                                  
2483                         ShortcutInfo si = ((ShortcutInfo) (info));                                       
2484                         if (si.isPromise() && (si.getTargetComponent() != null)) {                       
2485                             packagesToIgnore.add(si.getTargetComponent().getPackageName());              
2486                         }                                                                                
2487                     } else if (info instanceof LauncherAppWidgetInfo) {                                  
2488                         LauncherAppWidgetInfo lawi = ((LauncherAppWidgetInfo) (info));                   
2489                         if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {        
2490                             packagesToIgnore.add(lawi.providerName.getPackageName());                    
2491                         }                                                                                
2492                     }                                                                                    
2493                 }                                                                                        
2494             }                                                                                            
2495             mIconCache.updateDbIcons(packagesToIgnore);                                                  
2496         }                                                                                                
2497                                                                                                          
2498         private void onlyBindAllApps() {                                                                 
2499             final Callbacks oldCallbacks = mCallbacks.get();                                             
2500             if (oldCallbacks == null) {                                                                  
2501                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2502                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2503                 return;                                                                                  
2504             }                                                                                            
2505             // shallow copy                                                                              
2506             @SuppressWarnings("unchecked")                                                               
2507             final ArrayList<AppInfo> list = ((ArrayList<AppInfo>) (mBgAllAppsList.data.clone()));        
2508             final WidgetsModel widgetList = mBgWidgetsModel.clone();                                     
2509             Runnable r = new Runnable() {                                                                
2510                 public void run() {                                                                      
2511                     final long t = SystemClock.uptimeMillis();                                           
2512                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2513                     if (callbacks != null) {                                                             
2514                         callbacks.bindAllApplications(list);                                             
2515                         callbacks.bindAllPackages(widgetList);                                           
2516                     }                                                                                    
2517                     if (DEBUG_LOADERS) {                                                                 
2518                         Log.d(TAG, ((("bound all " + list.size()) + " apps from cache in ") + (SystemCloc🔵
2519                     }                                                                                    
2520                 }                                                                                        
2521             };                                                                                           
2522             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2523             if (isRunningOnMainThread) {                                                                 
2524                 r.run();                                                                                 
2525             } else {                                                                                     
2526                 mHandler.post(r);                                                                        
2527             }                                                                                            
2528         }                                                                                                
2529                                                                                                          
2530         private void loadAllApps() {                                                                     
2531             final long loadTime = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                      
2532             final Callbacks oldCallbacks = mCallbacks.get();                                             
2533             if (oldCallbacks == null) {                                                                  
2534                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2535                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2536                 return;                                                                                  
2537             }                                                                                            
2538             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2539             // Clear the list of apps                                                                    
2540             mBgAllAppsList.clear();                                                                      
2541             for (UserHandleCompat user : profiles) {                                                     
2542                 // Query for the set of apps                                                             
2543                 final long qiaTime = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                   
2544                 final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user); 
2545                 if (DEBUG_LOADERS) {                                                                     
2546                     Log.d(TAG, (("getActivityList took " + (SystemClock.uptimeMillis() - qiaTime)) + "ms 🔵
2547                     Log.d(TAG, (("getActivityList got " + apps.size()) + " apps for user ") + user);     
2548                 }                                                                                        
2549                 // Fail if we don't have any apps                                                        
2550                 // TODO: Fix this. Only fail for the current user.                                       
2551                 if ((apps == null) || apps.isEmpty()) {                                                  
2552                     return;                                                                              
2553                 }                                                                                        
2554                 // Create the ApplicationInfos                                                           
2555                 for (int i = 0; i < apps.size(); i++) {                                                  
2556                     LauncherActivityInfoCompat app = apps.get(i);                                        
2557                     // This builds the icon bitmaps.                                                     
2558                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2559                 }                                                                                        
2560                 final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);   
2561                 if (heuristic != null) {                                                                 
2562                     runAfterBindCompletes(new Runnable() {                                               
2563                         @Override                                                                        
2564                         public void run() {                                                              
2565                             heuristic.processUserApps(apps);                                             
2566                         }                                                                                
2567                     });                                                                                  
2568                 }                                                                                        
2569             }                                                                                            
2570             // Huh? Shouldn't this be inside the Runnable below?                                         
2571             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2572             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2573             // Post callback on main thread                                                              
2574             mHandler.post(new Runnable() {                                                               
2575                 public void run() {                                                                      
2576                     final long bindTime = SystemClock.uptimeMillis();                                    
2577                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2578                     if (callbacks != null) {                                                             
2579                         callbacks.bindAllApplications(added);                                            
2580                         if (DEBUG_LOADERS) {                                                             
2581                             Log.d(TAG, ((("bound " + added.size()) + " apps in ") + (SystemClock.uptimeMi🔵
2582                         }                                                                                
2583                     } else {                                                                             
2584                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2585                     }                                                                                    
2586                 }                                                                                        
2587             });                                                                                          
2588             // Cleanup any data stored for a deleted user.                                               
2589             ManagedProfileHeuristic.processAllUsers(profiles, mContext);                                 
2590                     /* refresh */                                                                        
2591             loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks), true);      
2592             if (DEBUG_LOADERS) {                                                                         
2593                 Log.d(TAG, ("Icons processed in " + (SystemClock.uptimeMillis() - loadTime)) + "ms");    
2594             }                                                                                            
2595         }                                                                                                
2596                                                                                                          
2597         public void dumpState() {                                                                        
2598             synchronized(sBgLock) {                                                                      
2599                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2600                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2601                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2602                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2603             }                                                                                            
2604         }                                                                                                
2605     }                                                                                                    
2606                                                                                                          
2607     /**                                                                                                  
2608      * Called when the icons for packages have been updated in the icon cache.                           
2609      */                                                                                                  
2610     public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {          
2611         final Callbacks callbacks = getCallback();                                                       
2612         final ArrayList<AppInfo> updatedApps = new ArrayList<>();                                        
2613         final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();                              
2614         // If any package icon has changed (app was updated while launcher was dead),                    
2615         // update the corresponding shortcuts.                                                           
2616         synchronized(sBgLock) {                                                                          
2617             for (ItemInfo info : sBgItemsIdMap) {                                                        
2618                 if (((info instanceof ShortcutInfo) && user.equals(info.user)) && (info.itemType == Launc🔵
2619                     ShortcutInfo si = ((ShortcutInfo) (info));                                           
2620                     ComponentName cn = si.getTargetComponent();                                          
2621                     if ((cn != null) && updatedPackages.contains(cn.getPackageName())) {                 
2622                         si.updateIcon(mIconCache);                                                       
2623                         updatedShortcuts.add(si);                                                        
2624                     }                                                                                    
2625                 }                                                                                        
2626             }                                                                                            
2627             mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);                     
2628         }                                                                                                
2629         if (!updatedShortcuts.isEmpty()) {                                                               
2630             final UserHandleCompat userFinal = user;                                                     
2631             mHandler.post(new Runnable() {                                                               
2632                 public void run() {                                                                      
2633                     Callbacks cb = getCallback();                                                        
2634                     if ((cb != null) && (callbacks == cb)) {                                             
2635                         cb.bindShortcutsChanged(updatedShortcuts, new ArrayList<ShortcutInfo>(), userFina🔵
2636                     }                                                                                    
2637                 }                                                                                        
2638             });                                                                                          
2639         }                                                                                                
2640         if (!updatedApps.isEmpty()) {                                                                    
2641             mHandler.post(new Runnable() {                                                               
2642                 public void run() {                                                                      
2643                     Callbacks cb = getCallback();                                                        
2644                     if ((cb != null) && (callbacks == cb)) {                                             
2645                         cb.bindAppsUpdated(updatedApps);                                                 
2646                     }                                                                                    
2647                 }                                                                                        
2648             });                                                                                          
2649         }                                                                                                
2650         // Reload widget list. No need to refresh, as we only want to update the icons and labels.       
2651         loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);                             
2652     }                                                                                                    
2653                                                                                                          
2654     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2655         sWorker.post(task);                                                                              
2656     }                                                                                                    
2657                                                                                                          
2658     @Thunk                                                                                               
2659     class AppsAvailabilityCheck extends BroadcastReceiver {                                              
2660         @Override                                                                                        
2661         public void onReceive(Context context, Intent intent) {                                          
2662             synchronized (sBgLock) {                                                                     
2663                 final LauncherAppsCompat launcherApps = LauncherAppsCompat                               
2664                         .getInstance(mApp.getContext());                                                 
2665                 final PackageManager manager = context.getPackageManager();                              
2666                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
2667                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
2668                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
2669                     UserHandleCompat user = entry.getKey();                                              
2670                     packagesRemoved.clear();                                                             
2671                     packagesUnavailable.clear();                                                         
2672                     for (String pkg : entry.getValue()) {                                                
2673                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
2674                             boolean packageOnSdcard = launcherApps.isAppEnabled(                         
2675                                     manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);              
2676                             if (packageOnSdcard) {                                                       
2677                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
2678                                 packagesUnavailable.add(pkg);                                            
2679                             } else {                                                                     
2680                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
2681                                 packagesRemoved.add(pkg);                                                
2682                             }                                                                            
2683                         }                                                                                
2684                     }                                                                                    
2685                     if (!packagesRemoved.isEmpty()) {                                                    
2686                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,       
2687                                 packagesRemoved.toArray(new String[packagesRemoved.size()]), user));     
2688                     }                                                                                    
2689                     if (!packagesUnavailable.isEmpty()) {                                                
2690                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,  
2691                                 packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user🔵
2692                     }                                                                                    
2693                 }                                                                                        
2694                 sPendingPackages.clear();                                                                
2695             }                                                                                            
2696         }                                                                                                
2697     }                                                                                                    
2698                                                                                                          
2699     private class PackageUpdatedTask implements Runnable {                                               
2700         int mOp;                                                                                         
2701                                                                                                          
2702         String[] mPackages;                                                                              
2703                                                                                                          
2704         UserHandleCompat mUser;                                                                          
2705                                                                                                          
2706         public static final int OP_NONE = 0;                                                             
2707                                                                                                          
2708         public static final int OP_ADD = 1;                                                              
2709                                                                                                          
2710         public static final int OP_UPDATE = 2;                                                           
2711                                                                                                          
2712         // uninstlled                                                                                    
2713         public static final int OP_REMOVE = 3; // uninstlled                                             
2714                                                                                                          
2715         // external media unmounted                                                                      
2716         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2717                                                                                                          
2718         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
2719             mOp = op;                                                                                    
2720             mPackages = packages;                                                                        
2721             mUser = user;                                                                                
2722         }                                                                                                
2723                                                                                                          
2724         public void run() {                                                                              
2725             if (!mHasLoaderCompletedOnce) {                                                              
2726                 // Loader has not yet run.                                                               
2727                 return;                                                                                  
2728             }                                                                                            
2729             final Context context = mApp.getContext();                                                   
2730             final String[] packages = mPackages;                                                         
2731             final int N = packages.length;                                                               
2732             switch (mOp) {                                                                               
2733                 case OP_ADD :                                                                            
2734                     {                                                                                    
2735                         for (int i = 0; i < N; i++) {                                                    
2736                             if (DEBUG_LOADERS) {                                                         
2737                                 Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                    
2738                             }                                                                            
2739                             mIconCache.updateIconsForPkg(packages[i], mUser);                            
2740                             mBgAllAppsList.addPackage(context, packages[i], mUser);                      
2741                         }                                                                                
2742                         ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser); 
2743                         if (heuristic != null) {                                                         
2744                             heuristic.processPackageAdd(mPackages);                                      
2745                         }                                                                                
2746                         break;                                                                           
2747                     }                                                                                    
2748                 case OP_UPDATE :                                                                         
2749                     for (int i = 0; i < N; i++) {                                                        
2750                         if (DEBUG_LOADERS) {                                                             
2751                             Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);                     
2752                         }                                                                                
2753                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2754                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
2755                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
2756                     }                                                                                    
2757                     break;                                                                               
2758                 case OP_REMOVE :                                                                         
2759                     {                                                                                    
2760                         ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser); 
2761                         if (heuristic != null) {                                                         
2762                             heuristic.processPackageRemoved(mPackages);                                  
2763                         }                                                                                
2764                         for (int i = 0; i < N; i++) {                                                    
2765                             if (DEBUG_LOADERS) {                                                         
2766                                 Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);                 
2767                             }                                                                            
2768                             mIconCache.removeIconsForPkg(packages[i], mUser);                            
2769                         }                                                                                
2770                     // Fall through                                                                      
2771                     }                                                                                    
2772                 case OP_UNAVAILABLE :                                                                    
2773                     for (int i = 0; i < N; i++) {                                                        
2774                         if (DEBUG_LOADERS) {                                                             
2775                             Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);                     
2776                         }                                                                                
2777                         mBgAllAppsList.removePackage(packages[i], mUser);                                
2778                         mApp.getWidgetCache().removePackage(packages[i], mUser);                         
2779                     }                                                                                    
2780                     break;                                                                               
2781             }                                                                                            
2782             ArrayList<AppInfo> added = null;                                                             
2783             ArrayList<AppInfo> modified = null;                                                          
2784             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
2785             if (mBgAllAppsList.added.size() > 0) {                                                       
2786                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
2787                 mBgAllAppsList.added.clear();                                                            
2788             }                                                                                            
2789             if (mBgAllAppsList.modified.size() > 0) {                                                    
2790                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
2791                 mBgAllAppsList.modified.clear();                                                         
2792             }                                                                                            
2793             if (mBgAllAppsList.removed.size() > 0) {                                                     
2794                 removedApps.addAll(mBgAllAppsList.removed);                                              
2795                 mBgAllAppsList.removed.clear();                                                          
2796             }                                                                                            
2797             final Callbacks callbacks = getCallback();                                                   
2798             if (callbacks == null) {                                                                     
2799                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
2800                 return;                                                                                  
2801             }                                                                                            
2802             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps = new HashMap<ComponentName, AppInfo🔵
2803             if (added != null) {                                                                         
2804                 addAppsToAllApps(context, added);                                                        
2805                 for (AppInfo ai : added) {                                                               
2806                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
2807                 }                                                                                        
2808             }                                                                                            
2809             if (modified != null) {                                                                      
2810                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
2811                 for (AppInfo ai : modified) {                                                            
2812                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
2813                 }                                                                                        
2814                 mHandler.post(new Runnable() {                                                           
2815                     public void run() {                                                                  
2816                         Callbacks cb = getCallback();                                                    
2817                         if ((callbacks == cb) && (cb != null)) {                                         
2818                             callbacks.bindAppsUpdated(modifiedFinal);                                    
2819                         }                                                                                
2820                     }                                                                                    
2821                 });                                                                                      
2822             }                                                                                            
2823             // Update shortcut infos                                                                     
2824             if ((mOp == OP_ADD) || (mOp == OP_UPDATE)) {                                                 
2825                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
2826                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
2827                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
2828                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
2829                 synchronized(sBgLock) {                                                                  
2830                     for (ItemInfo info : sBgItemsIdMap) {                                                
2831                         if ((info instanceof ShortcutInfo) && mUser.equals(info.user)) {                 
2832                             ShortcutInfo si = ((ShortcutInfo) (info));                                   
2833                             boolean infoUpdated = false;                                                 
2834                             boolean shortcutUpdated = false;                                             
2835                             // Update shortcuts which use iconResource.                                  
2836                             if ((si.iconResource != null) && packageSet.contains(si.iconResource.packageN🔵
2837                                 Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName, si.🔵
2838                                 if (icon != null) {                                                      
2839                                     si.setIcon(icon);                                                    
2840                                     si.usingFallbackIcon = false;                                        
2841                                     infoUpdated = true;                                                  
2842                                 }                                                                        
2843                             }                                                                            
2844                             ComponentName cn = si.getTargetComponent();                                  
2845                             if ((cn != null) && packageSet.contains(cn.getPackageName())) {              
2846                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
2847                                 if (si.isPromise()) {                                                    
2848                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
2849                                         // Auto install icon                                             
2850                                         PackageManager pm = context.getPackageManager();                 
2851                                         ResolveInfo matched = pm.resolveActivity(new Intent(Intent.ACTION🔵
2852                                         if (matched == null) {                                           
2853                                             // Try to find the best match activity.                      
2854                                             Intent intent = pm.getLaunchIntentForPackage(cn.getPackageNam🔵
2855                                             if (intent != null) {                                        
2856                                                 cn = intent.getComponent();                              
2857                                                 appInfo = addedOrUpdatedApps.get(cn);                    
2858                                             }                                                            
2859                                             if ((intent == null) || (appInfo == null)) {                 
2860                                                 removedShortcuts.add(si);                                
2861                                                 continue;                                                
2862                                             }                                                            
2863                                             si.promisedIntent = intent;                                  
2864                                         }                                                                
2865                                     }                                                                    
2866                                     // Restore the shortcut.                                             
2867                                     if (appInfo != null) {                                               
2868                                         si.flags = appInfo.flags;                                        
2869                                     }                                                                    
2870                                     si.intent = si.promisedIntent;                                       
2871                                     si.promisedIntent = null;                                            
2872                                     si.status = ShortcutInfo.DEFAULT;                                    
2873                                     infoUpdated = true;                                                  
2874                                     si.updateIcon(mIconCache);                                           
2875                                 }                                                                        
2876                                 if (((appInfo != null) && Intent.ACTION_MAIN.equals(si.intent.getAction()🔵
2877                                     si.updateIcon(mIconCache);                                           
2878                                     si.title = Utilities.trim(appInfo.title);                            
2879                                     si.contentDescription = appInfo.contentDescription;                  
2880                                     infoUpdated = true;                                                  
2881                                 }                                                                        
2882                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
2883                                     // Since package was just updated, the target must be available now. 
2884                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
2885                                     shortcutUpdated = true;                                              
2886                                 }                                                                        
2887                             }                                                                            
2888                             if (infoUpdated || shortcutUpdated) {                                        
2889                                 updatedShortcuts.add(si);                                                
2890                             }                                                                            
2891                             if (infoUpdated) {                                                           
2892                                 updateItemInDatabase(context, si);                                       
2893                             }                                                                            
2894                         } else if (info instanceof LauncherAppWidgetInfo) {                              
2895                             LauncherAppWidgetInfo widgetInfo = ((LauncherAppWidgetInfo) (info));         
2896                             if ((mUser.equals(widgetInfo.user) && widgetInfo.hasRestoreFlag(LauncherAppWi🔵
2897                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
2898                                 widgets.add(widgetInfo);                                                 
2899                                 updateItemInDatabase(context, widgetInfo);                               
2900                             }                                                                            
2901                         }                                                                                
2902                     }                                                                                    
2903                 }                                                                                        
2904                 if ((!updatedShortcuts.isEmpty()) || (!removedShortcuts.isEmpty())) {                    
2905                     mHandler.post(new Runnable() {                                                       
2906                         public void run() {                                                              
2907                             Callbacks cb = getCallback();                                                
2908                             if ((callbacks == cb) && (cb != null)) {                                     
2909                                 callbacks.bindShortcutsChanged(updatedShortcuts, removedShortcuts, mUser)🔵
2910                             }                                                                            
2911                         }                                                                                
2912                     });                                                                                  
2913                     if (!removedShortcuts.isEmpty()) {                                                   
2914                         deleteItemsFromDatabase(context, removedShortcuts);                              
2915                     }                                                                                    
2916                 }                                                                                        
2917                 if (!widgets.isEmpty()) {                                                                
2918                     mHandler.post(new Runnable() {                                                       
2919                         public void run() {                                                              
2920                             Callbacks cb = getCallback();                                                
2921                             if ((callbacks == cb) && (cb != null)) {                                     
2922                                 callbacks.bindWidgetsRestored(widgets);                                  
2923                             }                                                                            
2924                         }                                                                                
2925                     });                                                                                  
2926                 }                                                                                        
2927             }                                                                                            
2928             final ArrayList<String> removedPackageNames = new ArrayList<String>();                       
2929             if ((mOp == OP_REMOVE) || (mOp == OP_UNAVAILABLE)) {                                         
2930                 // Mark all packages in the broadcast to be removed                                      
2931                 removedPackageNames.addAll(Arrays.asList(packages));                                     
2932             } else if (mOp == OP_UPDATE) {                                                               
2933                 // Mark disabled packages in the broadcast to be removed                                 
2934                 for (int i = 0; i < N; i++) {                                                            
2935                     if (isPackageDisabled(context, packages[i], mUser)) {                                
2936                         removedPackageNames.add(packages[i]);                                            
2937                     }                                                                                    
2938                 }                                                                                        
2939             }                                                                                            
2940             if ((!removedPackageNames.isEmpty()) || (!removedApps.isEmpty())) {                          
2941                 final int removeReason;                                                                  
2942                 if (mOp == OP_UNAVAILABLE) {                                                             
2943                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
2944                 } else {                                                                                 
2945                     // Remove all the components associated with this package                            
2946                     for (String pn : removedPackageNames) {                                              
2947                         deletePackageFromDatabase(context, pn, mUser);                                   
2948                     }                                                                                    
2949                     // Remove all the specific components                                                
2950                     for (AppInfo a : removedApps) {                                                      
2951                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
2952                         deleteItemsFromDatabase(context, infos);                                         
2953                     }                                                                                    
2954                     removeReason = 0;                                                                    
2955                 }                                                                                        
2956                 // Remove any queued items from the install queue                                        
2957                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
2958                 // Call the components-removed callback                                                  
2959                 mHandler.post(new Runnable() {                                                           
2960                     public void run() {                                                                  
2961                         Callbacks cb = getCallback();                                                    
2962                         if ((callbacks == cb) && (cb != null)) {                                         
2963                             callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser, remo🔵
2964                         }                                                                                
2965                     }                                                                                    
2966                 });                                                                                      
2967             }                                                                                            
2968             // onProvidersChanged method (API >= 17) already refreshed the widget list                   
2969             loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17);              
2970             // Write all the logs to disk                                                                
2971             mHandler.post(new Runnable() {                                                               
2972                 public void run() {                                                                      
2973                     Callbacks cb = getCallback();                                                        
2974                     if ((callbacks == cb) && (cb != null)) {                                             
2975                         callbacks.dumpLogsToLocalData();                                                 
2976                     }                                                                                    
2977                 }                                                                                        
2978             });                                                                                          
2979         }                                                                                                
2980     }                                                                                                    
2981                                                                                                          
2982     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,                
2983             boolean refresh) {                                                                           
2984         ArrayList<LauncherAppWidgetProviderInfo> results =                                               
2985                 new ArrayList<LauncherAppWidgetProviderInfo>();                                          
2986         try {                                                                                            
2987             synchronized (sBgLock) {                                                                     
2988                 if (sBgWidgetProviders == null || refresh) {                                             
2989                     HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders              
2990                             = new HashMap<>();                                                           
2991                     AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);             
2992                     LauncherAppWidgetProviderInfo info;                                                  
2993                                                                                                          
2994                     List<AppWidgetProviderInfo> widgets = wm.getAllProviders();                          
2995                     for (AppWidgetProviderInfo pInfo : widgets) {                                        
2996                         info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);           
2997                         UserHandleCompat user = wm.getUser(info);                                        
2998                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
2999                     }                                                                                    
3000                                                                                                          
3001                     Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values(); 
3002                     for (CustomAppWidget widget : customWidgets) {                                       
3003                         info = new LauncherAppWidgetProviderInfo(context, widget);                       
3004                         UserHandleCompat user = wm.getUser(info);                                        
3005                         tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);             
3006                     }                                                                                    
3007                     // Replace the global list at the very end, so that if there is an exception,        
3008                     // previously loaded provider list is used.                                          
3009                     sBgWidgetProviders = tmpWidgetProviders;                                             
3010                 }                                                                                        
3011                 results.addAll(sBgWidgetProviders.values());                                             
3012                 return results;                                                                          
3013             }                                                                                            
3014         } catch (Exception e) {                                                                          
3015             if (e.getCause() instanceof TransactionTooLargeException) {                                  
3016                 // the returned value may be incomplete and will not be refreshed until the next         
3017                 // time Launcher starts.                                                                 
3018                 // TODO: after figuring out a repro step, introduce a dirty bit to check when            
3019                 // onResume is called to refresh the widget provider list.                               
3020                 synchronized (sBgLock) {                                                                 
3021                     if (sBgWidgetProviders != null) {                                                    
3022                         results.addAll(sBgWidgetProviders.values());                                     
3023                     }                                                                                    
3024                     return results;                                                                      
3025                 }                                                                                        
3026             } else {                                                                                     
3027                 throw e;                                                                                 
3028             }                                                                                            
3029         }                                                                                                
3030     }                                                                                                    
3031                                                                                                          
3032     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,         
3033             UserHandleCompat user) {                                                                     
3034         synchronized (sBgLock) {                                                                         
3035             if (sBgWidgetProviders == null) {                                                            
3036                 getWidgetProviders(ctx, false /* refresh */);                                            
3037             }                                                                                            
3038             return sBgWidgetProviders.get(new ComponentKey(name, user));                                 
3039         }                                                                                                
3040     }                                                                                                    
3041                                                                                                          
3042     public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks, final bo🔵
3043         runOnWorkerThread(new Runnable() {                                                               
3044             @Override                                                                                    
3045             public void run() {                                                                          
3046                 updateWidgetsModel(context, refresh);                                                    
3047                 final WidgetsModel model = mBgWidgetsModel.clone();                                      
3048                 mHandler.post(new Runnable() {                                                           
3049                     @Override                                                                            
3050                     public void run() {                                                                  
3051                         Callbacks cb = getCallback();                                                    
3052                         if ((callbacks == cb) && (cb != null)) {                                         
3053                             callbacks.bindAllPackages(model);                                            
3054                         }                                                                                
3055                     }                                                                                    
3056                 });                                                                                      
3057                 // update the Widget entries inside DB on the worker thread.                             
3058                 LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(model.getRawList()🔵
3059             }                                                                                            
3060         });                                                                                              
3061     }                                                                                                    
3062                                                                                                          
3063     /**                                                                                                  
3064      * Returns a list of ResolveInfos/AppWidgetInfos.                                                    
3065      *                                                                                                   
3066      * @see #loadAndBindWidgetsAndShortcuts                                                              
3067      */                                                                                                  
3068     @Thunk                                                                                               
3069     void updateWidgetsModel(Context context, boolean refresh) {                                          
3070         PackageManager packageManager = context.getPackageManager();                                     
3071         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3072         widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));                                
3073         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3074         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3075         mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);                                     
3076     }                                                                                                    
3077                                                                                                          
3078     @Thunk                                                                                               
3079     static boolean isPackageDisabled(Context context, String packageName, UserHandleCompat user) {       
3080         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3081         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3082     }                                                                                                    
3083                                                                                                          
3084     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3085             UserHandleCompat user) {                                                                     
3086         if (cn == null) {                                                                                
3087             return false;                                                                                
3088         }                                                                                                
3089         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3090         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3091             return false;                                                                                
3092         }                                                                                                
3093         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3094     }                                                                                                    
3095                                                                                                          
3096     public static boolean isValidPackage(Context context, String packageName,                            
3097             UserHandleCompat user) {                                                                     
3098         if (packageName == null) {                                                                       
3099             return false;                                                                                
3100         }                                                                                                
3101         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3102         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3103     }                                                                                                    
3104                                                                                                          
3105     /**                                                                                                  
3106      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3107      * to a package that is not yet installed on the system.                                             
3108      */                                                                                                  
3109     public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent, int promiseType, int🔵
3110         final ShortcutInfo info = new ShortcutInfo();                                                    
3111         info.user = UserHandleCompat.myUserHandle();                                                     
3112         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3113         // the fallback icon                                                                             
3114         if (icon == null) {                                                                              
3115             /* useLowResIcon */                                                                          
3116             mIconCache.getTitleAndIcon(info, intent, info.user, false);                                  
3117         } else {                                                                                         
3118             info.setIcon(icon);                                                                          
3119         }                                                                                                
3120         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3121             String title = (c != null) ? c.getString(titleIndex) : null;                                 
3122             if (!TextUtils.isEmpty(title)) {                                                             
3123                 info.title = Utilities.trim(title);                                                      
3124             }                                                                                            
3125         } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                             
3126             if (TextUtils.isEmpty(info.title)) {                                                         
3127                 info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";                 
3128             }                                                                                            
3129         } else {                                                                                         
3130             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3131         }                                                                                                
3132         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3133         info.itemType = itemType;                                                                        
3134         info.promisedIntent = intent;                                                                    
3135         info.status = promiseType;                                                                       
3136         return info;                                                                                     
3137     }                                                                                                    
3138                                                                                                          
3139     /**                                                                                                  
3140      * Make an Intent object for a restored application or shortcut item that points                     
3141      * to the market page for the item.                                                                  
3142      */                                                                                                  
3143     @Thunk                                                                                               
3144     Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                             
3145         ComponentName componentName = intent.getComponent();                                             
3146         return getMarketIntent(componentName.getPackageName());                                          
3147     }                                                                                                    
3148                                                                                                          
3149     static Intent getMarketIntent(String packageName) {                                                  
3150         return new Intent(Intent.ACTION_VIEW)                                                            
3151             .setData(new Uri.Builder()                                                                   
3152                 .scheme("market")                                                                        
3153                 .authority("details")                                                                    
3154                 .appendQueryParameter("id", packageName)                                                 
3155                 .build());                                                                               
3156     }                                                                                                    
3157                                                                                                          
3158     /**                                                                                                  
3159      * Make an ShortcutInfo object for a shortcut that is an application.                                
3160      *                                                                                                   
3161      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3162      */                                                                                                  
3163     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent, UserHandleCompat user, 🔵
3164         if (user == null) {                                                                              
3165             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3166             return null;                                                                                 
3167         }                                                                                                
3168         ComponentName componentName = intent.getComponent();                                             
3169         if (componentName == null) {                                                                     
3170             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3171             return null;                                                                                 
3172         }                                                                                                
3173         Intent newIntent = new Intent(intent.getAction(), null);                                         
3174         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3175         newIntent.setComponent(componentName);                                                           
3176         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3177         if ((lai == null) && (!allowMissingTarget)) {                                                    
3178             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3179             return null;                                                                                 
3180         }                                                                                                
3181         final ShortcutInfo info = new ShortcutInfo();                                                    
3182         mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);                
3183         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && (c != null)) {                   
3184             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3185             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3186         }                                                                                                
3187         // from the db                                                                                   
3188         if (TextUtils.isEmpty(info.title) && (c != null)) {                                              
3189             info.title = Utilities.trim(c.getString(titleIndex));                                        
3190         }                                                                                                
3191         // fall back to the class name of the activity                                                   
3192         if (info.title == null) {                                                                        
3193             info.title = componentName.getClassName();                                                   
3194         }                                                                                                
3195         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3196         info.user = user;                                                                                
3197         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3198         if (lai != null) {                                                                               
3199             info.flags = AppInfo.initFlags(lai);                                                         
3200         }                                                                                                
3201         return info;                                                                                     
3202     }                                                                                                    
3203                                                                                                          
3204     static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos, ItemInfoFilter f) {             
3205         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3206         for (ItemInfo i : infos) {                                                                       
3207             if (i instanceof ShortcutInfo) {                                                             
3208                 ShortcutInfo info = ((ShortcutInfo) (i));                                                
3209                 ComponentName cn = info.getTargetComponent();                                            
3210                 if ((cn != null) && f.filterItem(null, info, cn)) {                                      
3211                     filtered.add(info);                                                                  
3212                 }                                                                                        
3213             } else if (i instanceof FolderInfo) {                                                        
3214                 FolderInfo info = ((FolderInfo) (i));                                                    
3215                 for (ShortcutInfo s : info.contents) {                                                   
3216                     ComponentName cn = s.getTargetComponent();                                           
3217                     if ((cn != null) && f.filterItem(info, s, cn)) {                                     
3218                         filtered.add(s);                                                                 
3219                     }                                                                                    
3220                 }                                                                                        
3221             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3222                 LauncherAppWidgetInfo info = ((LauncherAppWidgetInfo) (i));                              
3223                 ComponentName cn = info.providerName;                                                    
3224                 if ((cn != null) && f.filterItem(null, info, cn)) {                                      
3225                     filtered.add(info);                                                                  
3226                 }                                                                                        
3227             }                                                                                            
3228         }                                                                                                
3229         return new ArrayList<ItemInfo>(filtered);                                                        
3230     }                                                                                                    
3231                                                                                                          
3232     @Thunk                                                                                               
3233     ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname, final UserHandleCompat use🔵
3234         ItemInfoFilter filter = new ItemInfoFilter() {                                                   
3235             @Override                                                                                    
3236             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3237                 if (info.user == null) {                                                                 
3238                     return cn.equals(cname);                                                             
3239                 } else {                                                                                 
3240                     return cn.equals(cname) && info.user.equals(user);                                   
3241                 }                                                                                        
3242             }                                                                                            
3243         };                                                                                               
3244         return filterItemInfos(sBgItemsIdMap, filter);                                                   
3245     }                                                                                                    
3246                                                                                                          
3247     /**                                                                                                  
3248      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3249      */                                                                                                  
3250     @Thunk                                                                                               
3251     ShortcutInfo getShortcutInfo(Cursor c, Context context, int titleIndex, CursorIconInfo iconInfo) {   
3252         final ShortcutInfo info = new ShortcutInfo();                                                    
3253         // Non-app shortcuts are only supported for current user.                                        
3254         info.user = UserHandleCompat.myUserHandle();                                                     
3255         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3256         // TODO: If there's an explicit component and we can't install that, delete it.                  
3257         info.title = Utilities.trim(c.getString(titleIndex));                                            
3258         Bitmap icon = iconInfo.loadIcon(c, info, context);                                               
3259         // the fallback icon                                                                             
3260         if (icon == null) {                                                                              
3261             icon = mIconCache.getDefaultIcon(info.user);                                                 
3262             info.usingFallbackIcon = true;                                                               
3263         }                                                                                                
3264         info.setIcon(icon);                                                                              
3265         return info;                                                                                     
3266     }                                                                                                    
3267                                                                                                          
3268     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3269         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3270         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3271         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3272         if (intent == null) {                                                                            
3273             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3274             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3275             return null;                                                                                 
3276         }                                                                                                
3277         Bitmap icon = null;                                                                              
3278         boolean customIcon = false;                                                                      
3279         ShortcutIconResource iconResource = null;                                                        
3280         if (bitmap instanceof Bitmap) {                                                                  
3281             icon = Utilities.createIconBitmap(((Bitmap) (bitmap)), context);                             
3282             customIcon = true;                                                                           
3283         } else {                                                                                         
3284             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3285             if (extra instanceof ShortcutIconResource) {                                                 
3286                 iconResource = ((ShortcutIconResource) (extra));                                         
3287                 icon = Utilities.createIconBitmap(iconResource.packageName, iconResource.resourceName, co🔵
3288             }                                                                                            
3289         }                                                                                                
3290         final ShortcutInfo info = new ShortcutInfo();                                                    
3291         // Only support intents for current user for now. Intents sent from other                        
3292         // users wouldn't get here without intent forwarding anyway.                                     
3293         info.user = UserHandleCompat.myUserHandle();                                                     
3294         if (icon == null) {                                                                              
3295             icon = mIconCache.getDefaultIcon(info.user);                                                 
3296             info.usingFallbackIcon = true;                                                               
3297         }                                                                                                
3298         info.setIcon(icon);                                                                              
3299         info.title = Utilities.trim(name);                                                               
3300         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);             
3301         info.intent = intent;                                                                            
3302         info.customIcon = customIcon;                                                                    
3303         info.iconResource = iconResource;                                                                
3304         return info;                                                                                     
3305     }                                                                                                    
3306                                                                                                          
3307     /**                                                                                                  
3308      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3309      * or make a new one.                                                                                
3310      */                                                                                                  
3311     @Thunk                                                                                               
3312     static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {                      
3313         // See if a placeholder was created for us already                                               
3314         FolderInfo folderInfo = folders.get(id);                                                         
3315         if (folderInfo == null) {                                                                        
3316             // No placeholder -- create a new instance                                                   
3317             folderInfo = new FolderInfo();                                                               
3318             folders.put(id, folderInfo);                                                                 
3319         }                                                                                                
3320         return folderInfo;                                                                               
3321     }                                                                                                    
3322                                                                                                          
3323     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3324         return (provider != null) && (provider.provider != null)                                         
3325                 && (provider.provider.getPackageName() != null);                                         
3326     }                                                                                                    
3327                                                                                                          
3328     public void dumpState() {                                                                            
3329         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3330         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3331         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3332         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3333         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3334         if (mLoaderTask != null) {                                                                       
3335             mLoaderTask.dumpState();                                                                     
3336         } else {                                                                                         
3337             Log.d(TAG, "mLoaderTask=null");                                                              
3338         }                                                                                                
3339     }                                                                                                    
3340                                                                                                          
3341     public Callbacks getCallback() {                                                                     
3342         return mCallbacks != null ? mCallbacks.get() : null;                                             
3343     }                                                                                                    
3344                                                                                                          
3345     /**                                                                                                  
3346      * @return {@link FolderInfo} if its already loaded.                                                 
3347      */                                                                                                  
3348     public FolderInfo findFolderById(Long folderId) {                                                    
3349         synchronized(sBgLock) {                                                                          
3350             return sBgFolders.get(folderId);                                                             
3351         }                                                                                                
3352     }                                                                                                    
3353                                                                                                          
3354     /**                                                                                                  
3355      * @return the looper for the worker thread which can be used to start background tasks.             
3356      */                                                                                                  
3357     public static Looper getWorkerLooper() {                                                             
3358         return sWorkerThread.getLooper();                                                                
3359     }                                                                                                    
3360 }                                                                                                        
















































































































































































































































































































































































































ours vs. base theirs vs. base
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetProviderInfo;                                                                   
  21  import android.content.BroadcastReceiver;                                                                         
  22  import android.content.ComponentName;                                                                             
  23 -import android.content.ContentProviderClient;                                                                     
  24  import android.content.ContentProviderOperation;                                                                  
  25  import android.content.ContentResolver;                                                                           
  26  import android.content.ContentValues;                                                                             
  27  import android.content.Context;                                                                                   
  28  import android.content.Intent;                                                                                    
  29  import android.content.Intent.ShortcutIconResource;                                                               
  30  import android.content.IntentFilter;                                                                              
  31 -import android.content.SharedPreferences;                                                                         
  32  import android.content.pm.PackageManager;                                                                         
  33  import android.content.pm.ProviderInfo;                                                                           
  34  import android.content.pm.ResolveInfo;                                                                            
  35 -import android.content.res.Configuration;                                                                         
  36 -import android.content.res.Resources;                                                                             
  37  import android.database.Cursor;                                                                                   
  38  import android.graphics.Bitmap;                                                                                   
  39 -import android.graphics.BitmapFactory;                                                                            
  40 -import android.graphics.Rect;                                                                                     
  41  import android.net.Uri;                                                                                           
  42  import android.os.Build;                                                                                          
  43  import android.os.Environment;                                                                                    
  44  import android.os.Handler;                                                                                        
  45  import android.os.HandlerThread;                                                                                  
  46 +import android.os.Looper;                                                                                         
  47  import android.os.Parcelable;                                                                                     
  48  import android.os.Process;                                                                                        
  49 -import android.os.RemoteException;                                                                                
  50  import android.os.SystemClock;                                                                                    
  51  import android.os.TransactionTooLargeException;                                                                   
  52  import android.provider.BaseColumns;                                                                              
  53  import android.text.TextUtils;                                                                                    
  54  import android.util.Log;                                                                                          
  55  import android.util.LongSparseArray;                                                                              
  56  import android.util.Pair;                                                                                         
  57                                                                                                                    
  58  import com.android.launcher3.compat.AppWidgetManagerCompat;                                                       
  59  import com.android.launcher3.compat.LauncherActivityInfoCompat;                                                   
  60  import com.android.launcher3.compat.LauncherAppsCompat;                                                           
  61  import com.android.launcher3.compat.PackageInstallerCompat;                                                       
  62  import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                                    
  63  import com.android.launcher3.compat.UserHandleCompat;                                                             
  64  import com.android.launcher3.compat.UserManagerCompat;                                                            
  65 +import com.android.launcher3.model.WidgetsModel;                                                                  
  66  import com.android.launcher3.util.ComponentKey;                                                                   
  67 +import com.android.launcher3.util.CursorIconInfo;                                                                 
  68 +import com.android.launcher3.util.LongArrayMap;                                                                   
  69 +import com.android.launcher3.util.ManagedProfileHeuristic;                                                        
  70 +import com.android.launcher3.util.Thunk;                                                                          
  71                                                                                                                    
  72  import java.lang.ref.WeakReference;                                                                               
  73  import java.net.URISyntaxException;                                                                               
  74  import java.security.InvalidParameterException;                                                                   
  75 -import java.text.Collator;                                                                                        
  76  import java.util.ArrayList;                                                                                       
  77  import java.util.Arrays;                                                                                          
  78  import java.util.Collection;                                                                                      
  79  import java.util.Collections;                                                                                     
  80  import java.util.Comparator;                                                                                      
  81  import java.util.HashMap;                                                                                         
  82  import java.util.HashSet;                                                                                         
  83  import java.util.Iterator;                                                                                        
  84  import java.util.List;                                                                                            
  85  import java.util.Map.Entry;                                                                                       
  86  import java.util.Set;                                                                                             
  87 -import java.util.TreeMap;                                                                                         
  88                                                                                                                    
  89  /**                                                                                                               
  90   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  91   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  92   * for the Launcher.                                                                                              
  93   */                                                                                                               
  94  public class LauncherModel extends BroadcastReceiver                                                              
  95          implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                               
  96      static final boolean DEBUG_LOADERS = false;                                                                   
  97      private static final boolean DEBUG_RECEIVER = false;                                                          
  98      private static final boolean REMOVE_UNRESTORED_ICONS = true;                                                  
  99 -    private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                           
 100                                                                                                                    
 101      static final String TAG = "Launcher.Model";                                                                   
 102                                                                                                                    
 103 -    // true = use a "More Apps" folder for non-workspace apps on upgrade                                          
 104 -    // false = strew non-workspace apps across the workspace on upgrade                                           
 105 -    public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                             
 106      public static final int LOADER_FLAG_NONE = 0;                                                                 
 107      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
 108      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
 109                                                                                                                    
 110      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
 111      private static final long INVALID_SCREEN_ID = -1L;                                                            
 112                                                                                                                    
 113 -    private final boolean mAppsCanBeOnRemoveableStorage;                                                          
 114 +    @Thunk final boolean mAppsCanBeOnRemoveableStorage;                                                           
 115      private final boolean mOldContentProviderExists;                                                              
 116                                                                                                                    
 117 -    private final LauncherAppState mApp;                                                                          
 118 -    private final Object mLock = new Object();                                                                    
 119 -    private DeferredHandler mHandler = new DeferredHandler();                                                     
 120 -    private LoaderTask mLoaderTask;                                                                               
 121 -    private boolean mIsLoaderTaskRunning;                                                                         
 122 -                                                                                                                  
 123 -    /**                                                                                                           
 124 -     * Maintain a set of packages per user, for which we added a shortcut on the workspace.                       
 125 -     */                                                                                                           
 126 -    private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";             
 127 -                                                                                                                  
 128 -    // Specific runnable types that are run on the main thread deferred handler, this allows us to                
 129 -    // clear all queued binding runnables when the Launcher activity is destroyed.                                
 130 -    private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
 131 -    private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    
 132 +    @Thunk final LauncherAppState mApp;                                                                           
 133 +    @Thunk final Object mLock = new Object();                                                                     
 134 +    @Thunk DeferredHandler mHandler = new DeferredHandler();                                                      
 135 +    @Thunk LoaderTask mLoaderTask;                                                                                
 136 +    @Thunk boolean mIsLoaderTaskRunning;                                                                          
 137 +    @Thunk boolean mHasLoaderCompletedOnce;                                                                       
 138                                                                                                                    
 139      private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                             
 140                                                                                                                    
 141 -    private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      
 142 +    @Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                       
 143      static {                                                                                                      
 144          sWorkerThread.start();                                                                                    
 145      }                                                                                                             
 146 -    private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                
 147 +    @Thunk static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                 
 148                                                                                                                    
 149      // We start off with everything not loaded.  After that, we assume that                                       
 150      // our monitoring of the package manager provides all updates and we never                                    
 151      // need to do a requery.  These are only ever touched from the loader thread.                                 
 152 -    private boolean mWorkspaceLoaded;                                                                             
 153 -    private boolean mAllAppsLoaded;                                                                               
 154 +    @Thunk boolean mWorkspaceLoaded;                                                                              
 155 +    @Thunk boolean mAllAppsLoaded;                                                                                
 156                                                                                                                    
 157      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 158      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 159      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 160      // a normal load, we also clear this set of Runnables.                                                        
 161      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 162                                                                                                                    
 163 -    private WeakReference<Callbacks> mCallbacks;                                                                  
 164 +    /**                                                                                                           
 165 +     * Set of runnables to be called on the background thread after the workspace binding                         
 166 +     * is complete.                                                                                               
 167 +     */                                                                                                           
 168 +    static final ArrayList<Runnable> mBindCompleteRunnables = new ArrayList<Runnable>();                          
 169 +                                                                                                                  
 170 +    @Thunk WeakReference<Callbacks> mCallbacks;                                                                   
 171                                                                                                                    
 172      // < only access in worker thread >                                                                           
 173      AllAppsList mBgAllAppsList;                                                                                   
 174 +    // Entire list of widgets.                                                                                    
 175 +    WidgetsModel mBgWidgetsModel;                                                                                 
 176                                                                                                                    
 177      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 178      // other locks, this one can generally be held long-term because we never expect any of these                 
 179      // static data structures to be referenced outside of the worker thread except on the first                   
 180      // load after configuration change.                                                                           
 181      static final Object sBgLock = new Object();                                                                   
 182                                                                                                                    
 183      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 184      // LauncherModel to their ids                                                                                 
 185 -    static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           
 186 +    static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();                                     
 187                                                                                                                    
 188      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 189      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 190      //       shortcuts within folders).                                                                           
 191      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 192                                                                                                                    
 193      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 194      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 195          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 196                                                                                                                    
 197      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 198 -    static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 199 -                                                                                                                  
 200 -    // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 201 -    static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          
 202 +    static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();                                      
 203                                                                                                                    
 204      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 205      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 206                                                                                                                    
 207      // sBgWidgetProviders is the set of widget providers including custom internal widgets                        
 208      public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;                        
 209                                                                                                                    
 210      // sPendingPackages is a set of packages which could be on sdcard and are not available yet                   
 211      static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                                    
 212              new HashMap<UserHandleCompat, HashSet<String>>();                                                     
 213                                                                                                                    
 214      // </ only access in worker thread >                                                                          
 215                                                                                                                    
 216 -    private IconCache mIconCache;                                                                                 
 217 -                                                                                                                  
 218 -    protected int mPreviousConfigMcc;                                                                             
 219 -                                                                                                                  
 220 -    private final LauncherAppsCompat mLauncherApps;                                                               
 221 -    private final UserManagerCompat mUserManager;                                                                 
 222 +    @Thunk IconCache mIconCache;                                                                                  
 223 +                                                                                                                  
 224 +    @Thunk final LauncherAppsCompat mLauncherApps;                                                                
 225 +    @Thunk final UserManagerCompat mUserManager;                                                                  
 226                                                                                                                    
 227      public interface Callbacks {                                                                                  
 228          public boolean setLoadOnResume();                                                                         
 229          public int getCurrentWorkspaceScreen();                                                                   
 230          public void startBinding();                                                                               
 231          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 232                                boolean forceAnimateIcons);                                                         
 233          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 234          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 235 -        public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 236 -        public void finishBindingItems(boolean upgradePath);                                                      
 237 +        public void bindFolders(LongArrayMap<FolderInfo> folders);                                                
 238 +        public void finishBindingItems();                                                                         
 239          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 240          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 241          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 242                                    ArrayList<ItemInfo> addNotAnimated,                                             
 243                                    ArrayList<ItemInfo> addAnimated,                                                
 244                                    ArrayList<AppInfo> addedApps);                                                  
 245          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 246          public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                         
 247                  ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                          
 248          public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                                
 249 -        public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                                
 250 -        public void updatePackageBadge(String packageName);                                                       
 251 +        public void bindRestoreItemsChange(HashSet<ItemInfo> updates);                                            
 252          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 253                          ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                          
 254 -        public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   
 255 +        public void bindAllPackages(WidgetsModel model);                                                          
 256          public void bindSearchablesChanged();                                                                     
 257          public boolean isAllAppsButtonRank(int rank);                                                             
 258          public void onPageBoundSynchronously(int page);                                                           
 259          public void dumpLogsToLocalData();                                                                        
 260 -        public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,                    
 261 -                int[] cell, int spanX, int spanY);                                                                
 262      }                                                                                                             
 263                                                                                                                    
 264      public interface ItemInfoFilter {                                                                             
 265          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 266 -    }                                                                                                             
 267 -                                                                                                                  
 268 -    public interface ScreenPosProvider {                                                                          
 269 -        int getScreenIndex(ArrayList<Long> screenIDs);                                                            
 270      }                                                                                                             
 271                                                                                                                    
 272      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 273          Context context = app.getContext();                                                                       
 274                                                                                                                    
 275          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 276          String oldProvider = context.getString(R.string.old_launcher_provider_uri);                               
 277          // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different                        
 278          // resource string.                                                                                       
 279          String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                         
 280          ProviderInfo providerInfo =                                                                               
 281                  context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                         
 282          ProviderInfo redirectProvider =                                                                           
 283                  context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                         
 284                                                                                                                    
 285          Log.d(TAG, "Old launcher provider: " + oldProvider);                                                      
 286          mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                         
 287                                                                                                                    
 288          if (mOldContentProviderExists) {                                                                          
 289              Log.d(TAG, "Old launcher provider exists.");                                                          
 290          } else {                                                                                                  
 291              Log.d(TAG, "Old launcher provider does not exist.");                                                  
 292          }                                                                                                         
 293                                                                                                                    
 294          mApp = app;                                                                                               
 295          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   
 296 +        mBgWidgetsModel = new WidgetsModel(context, iconCache, appFilter);                                        
 297          mIconCache = iconCache;                                                                                   
 298                                                                                                                    
 299 -        final Resources res = context.getResources();                                                             
 300 -        Configuration config = res.getConfiguration();                                                            
 301 -        mPreviousConfigMcc = config.mcc;                                                                          
 302          mLauncherApps = LauncherAppsCompat.getInstance(context);                                                  
 303          mUserManager = UserManagerCompat.getInstance(context);                                                    
 304      }                                                                                                             
 305                                                                                                                    
 306      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 307       * posted on the main thread handler. */                                                                      
 308 -    private void runOnMainThread(Runnable r) {                                                                    
 309 -        runOnMainThread(r, 0);                                                                                    
 310 -    }                                                                                                             
 311 -    private void runOnMainThread(Runnable r, int type) {                                                          
 312 +    @Thunk void runOnMainThread(Runnable r) {                                                                     
 313          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 314              // If we are on the worker thread, post onto the main handler                                         
 315              mHandler.post(r);                                                                                     
 316          } else {                                                                                                  
 317              r.run();                                                                                              
 318          }                                                                                                         
 319      }                                                                                                             
 320                                                                                                                    
 321      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 322       * posted on the worker thread handler. */                                                                    
 323      private static void runOnWorkerThread(Runnable r) {                                                           
 324          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 325              r.run();                                                                                              
 326          } else {                                                                                                  
 327              // If we are not on the worker thread, then post to the worker handler                                
 328              sWorker.post(r);                                                                                      
 329          }                                                                                                         
 330      }                                                                                                             
 331                                                                                                                    
 332 +    /**                                                                                                           
 333 +     * Runs the specified runnable after the loader is complete                                                   
 334 +     */                                                                                                           
 335 +    @Thunk void runAfterBindCompletes(Runnable r) {                                                               
 336 +        if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) {                                                   
 337 +            synchronized (mBindCompleteRunnables) {                                                               
 338 +                mBindCompleteRunnables.add(r);                                                                    
 339 +            }                                                                                                     
 340 +        } else {                                                                                                  
 341 +            runOnWorkerThread(r);                                                                                 
 342 +        }                                                                                                         
 343 +    }                                                                                                             
 344 +                                                                                                                  
 345      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 346          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 347      }                                                                                                             
 348                                                                                                                    
 349 -    public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                                
 350 -        // Process the updated package state                                                                      
 351 -        Runnable r = new Runnable() {                                                                             
 352 +    public void setPackageState(final PackageInstallInfo installInfo) {                                           
 353 +        Runnable updateRunnable = new Runnable() {                                                                
 354 +                                                                                                                  
 355 +            @Override                                                                                             
 356              public void run() {                                                                                   
 357 -                Callbacks callbacks = getCallback();                                                              
 358 -                if (callbacks != null) {                                                                          
 359 -                    callbacks.updatePackageState(installInfo);                                                    
 360 +                synchronized (sBgLock) {                                                                          
 361 +                    final HashSet<ItemInfo> updates = new HashSet<>();                                            
 362 +                                                                                                                  
 363 +                    if (installInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {                           
 364 +                        // Ignore install success events as they are handled by Package add events.               
 365 +                        return;                                                                                   
 366 +                    }                                                                                             
 367 +                                                                                                                  
 368 +                    for (ItemInfo info : sBgItemsIdMap) {                                                         
 369 +                        if (info instanceof ShortcutInfo) {                                                       
 370 +                            ShortcutInfo si = (ShortcutInfo) info;                                                
 371 +                            ComponentName cn = si.getTargetComponent();                                           
 372 +                            if (si.isPromise() && (cn != null)                                                    
 373 +                                    && installInfo.packageName.equals(cn.getPackageName())) {                     
 374 +                                si.setInstallProgress(installInfo.progress);                                      
 375 +                                                                                                                  
 376 +                                if (installInfo.state == PackageInstallerCompat.STATUS_FAILED) {                  
 377 +                                    // Mark this info as broken.                                                  
 378 +                                    si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                       
 379 +                                }                                                                                 
 380 +                                updates.add(si);                                                                  
 381 +                            }                                                                                     
 382 +                        }                                                                                         
 383 +                    }                                                                                             
 384 +                                                                                                                  
 385 +                    for (LauncherAppWidgetInfo widget : sBgAppWidgets) {                                          
 386 +                        if (widget.providerName.getPackageName().equals(installInfo.packageName)) {               
 387 +                            widget.installProgress = installInfo.progress;                                        
 388 +                            updates.add(widget);                                                                  
 389 +                        }                                                                                         
 390 +                    }                                                                                             
 391 +                                                                                                                  
 392 +                    if (!updates.isEmpty()) {                                                                     
 393 +                        // Push changes to the callback.                                                          
 394 +                        Runnable r = new Runnable() {                                                             
 395 +                            public void run() {                                                                   
 396 +                                Callbacks callbacks = getCallback();                                              
 397 +                                if (callbacks != null) {                                                          
 398 +                                    callbacks.bindRestoreItemsChange(updates);                                    
 399 +                                }                                                                                 
 400 +                            }                                                                                     
 401 +                        };                                                                                        
 402 +                        mHandler.post(r);                                                                         
 403 +                    }                                                                                             
 404                  }                                                                                                 
 405              }                                                                                                     
 406          };                                                                                                        
 407 -        mHandler.post(r);                                                                                         
 408 -    }                                                                                                             
 409 -                                                                                                                  
 410 -    public void updatePackageBadge(final String packageName) {                                                    
 411 -        // Process the updated package badge                                                                      
 412 -        Runnable r = new Runnable() {                                                                             
 413 +        runOnWorkerThread(updateRunnable);                                                                        
 414 +    }                                                                                                             
 415 +                                                                                                                  
 416 +    /**                                                                                                           
 417 +     * Updates the icons and label of all pending icons for the provided package name.                            
 418 +     */                                                                                                           
 419 +    public void updateSessionDisplayInfo(final String packageName) {                                              
 420 +        Runnable updateRunnable = new Runnable() {                                                                
 421 +                                                                                                                  
 422 +            @Override                                                                                             
 423              public void run() {                                                                                   
 424 -                Callbacks callbacks = getCallback();                                                              
 425 -                if (callbacks != null) {                                                                          
 426 -                    callbacks.updatePackageBadge(packageName);                                                    
 427 +                synchronized (sBgLock) {                                                                          
 428 +                    final ArrayList<ShortcutInfo> updates = new ArrayList<>();                                    
 429 +                    final UserHandleCompat user = UserHandleCompat.myUserHandle();                                
 430 +                                                                                                                  
 431 +                    for (ItemInfo info : sBgItemsIdMap) {                                                         
 432 +                        if (info instanceof ShortcutInfo) {                                                       
 433 +                            ShortcutInfo si = (ShortcutInfo) info;                                                
 434 +                            ComponentName cn = si.getTargetComponent();                                           
 435 +                            if (si.isPromise() && (cn != null)                                                    
 436 +                                    && packageName.equals(cn.getPackageName())) {                                 
 437 +                                if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                        
 438 +                                    // For auto install apps update the icon as well as label.                    
 439 +                                    mIconCache.getTitleAndIcon(si,                                                
 440 +                                            si.promisedIntent, user,                                              
 441 +                                            si.shouldUseLowResIcon());                                            
 442 +                                } else {                                                                          
 443 +                                    // Only update the icon for restored apps.                                    
 444 +                                    si.updateIcon(mIconCache);                                                    
 445 +                                }                                                                                 
 446 +                                updates.add(si);                                                                  
 447 +                            }                                                                                     
 448 +                        }                                                                                         
 449 +                    }                                                                                             
 450 +                                                                                                                  
 451 +                    if (!updates.isEmpty()) {                                                                     
 452 +                        // Push changes to the callback.                                                          
 453 +                        Runnable r = new Runnable() {                                                             
 454 +                            public void run() {                                                                   
 455 +                                Callbacks callbacks = getCallback();                                              
 456 +                                if (callbacks != null) {                                                          
 457 +                                    callbacks.bindShortcutsChanged(updates,                                       
 458 +                                            new ArrayList<ShortcutInfo>(), user);                                 
 459 +                                }                                                                                 
 460 +                            }                                                                                     
 461 +                        };                                                                                        
 462 +                        mHandler.post(r);                                                                         
 463 +                    }                                                                                             
 464                  }                                                                                                 
 465              }                                                                                                     
 466          };                                                                                                        
 467 -        mHandler.post(r);                                                                                         
 468 +        runOnWorkerThread(updateRunnable);                                                                        
 469      }                                                                                                             
 470                                                                                                                    
 471      public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 472          final Callbacks callbacks = getCallback();                                                                
 473                                                                                                                    
 474          if (allAppsApps == null) {                                                                                
 475              throw new RuntimeException("allAppsApps must not be null");                                           
 476          }                                                                                                         
 477          if (allAppsApps.isEmpty()) {                                                                              
 478              return;                                                                                               
 479          }                                                                                                         
 480                                                                                                                    
 481          // Process the newly added applications and add them to the database first                                
 482          Runnable r = new Runnable() {                                                                             
 483              public void run() {                                                                                   
 484                  runOnMainThread(new Runnable() {                                                                  
 485                      public void run() {                                                                           
 486                          Callbacks cb = getCallback();                                                             
 487                          if (callbacks == cb && cb != null) {                                                      
 488                              callbacks.bindAppsAdded(null, null, null, allAppsApps);                               
 489                          }                                                                                         
 490                      }                                                                                             
 491                  });                                                                                               
 492              }                                                                                                     
 493          };                                                                                                        
 494          runOnWorkerThread(r);                                                                                     
 495      }                                                                                                             
 496                                                                                                                    
 497 -    public void addAndBindAddedWorkspaceApps(final Context context,                                               
 498 -            final ArrayList<ItemInfo> workspaceApps) {                                                            
 499 -        addAndBindAddedWorkspaceApps(context, workspaceApps,                                                      
 500 -                new ScreenPosProvider() {                                                                         
 501 -                                                                                                                  
 502 -                    @Override                                                                                     
 503 -                    public int getScreenIndex(ArrayList<Long> screenIDs) {                                        
 504 -                        return screenIDs.isEmpty() ? 0 : 1;                                                       
 505 -                    }                                                                                             
 506 -                }, 1, false);                                                                                     
 507 -    }                                                                                                             
 508 -                                                                                                                  
 509 -    private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,                        
 510 +    private static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> occupiedPos,                    
 511              int[] xy, int spanX, int spanY) {                                                                     
 512          LauncherAppState app = LauncherAppState.getInstance();                                                    
 513 -        DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 514 -        final int xCount = (int) grid.numColumns;                                                                 
 515 -        final int yCount = (int) grid.numRows;                                                                    
 516 +        InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                         
 517 +        final int xCount = (int) profile.numColumns;                                                              
 518 +        final int yCount = (int) profile.numRows;                                                                 
 519          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 520          if (occupiedPos != null) {                                                                                
 521 -            for (Rect r : occupiedPos) {                                                                          
 522 -                for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                                  
 523 -                    for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                              
 524 +            for (ItemInfo r : occupiedPos) {                                                                      
 525 +                int right = r.cellX + r.spanX;                                                                    
 526 +                int bottom = r.cellY + r.spanY;                                                                   
 527 +                for (int x = r.cellX; 0 <= x && x < right && x < xCount; x++) {                                   
 528 +                    for (int y = r.cellY; 0 <= y && y < bottom && y < yCount; y++) {                              
 529                          occupied[x][y] = true;                                                                    
 530                      }                                                                                             
 531                  }                                                                                                 
 532              }                                                                                                     
 533          }                                                                                                         
 534 -        return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                             
 535 +        return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                              
 536      }                                                                                                             
 537                                                                                                                    
 538      /**                                                                                                           
 539       * Find a position on the screen for the given size or adds a new screen.                                     
 540       * @return screenId and the coordinates for the item.                                                         
 541       */                                                                                                           
 542 -    private static Pair<Long, int[]> findSpaceForItem(                                                            
 543 +    @Thunk Pair<Long, int[]> findSpaceForItem(                                                                    
 544              Context context,                                                                                      
 545 -            ScreenPosProvider preferredScreen,                                                                    
 546 -            int fallbackStartScreen,                                                                              
 547              ArrayList<Long> workspaceScreens,                                                                     
 548              ArrayList<Long> addedWorkspaceScreensFinal,                                                           
 549              int spanX, int spanY) {                                                                               
 550 -        // Load position of items which are on the desktop. We can't use sBgItemsIdMap because                    
 551 -        // loadWorkspace() may not have been called.                                                              
 552 -        final ContentResolver cr = context.getContentResolver();                                                  
 553 -        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 554 -                new String[] {                                                                                    
 555 -                    LauncherSettings.Favorites.SCREEN,                                                            
 556 -                    LauncherSettings.Favorites.CELLX,                                                             
 557 -                    LauncherSettings.Favorites.CELLY,                                                             
 558 -                    LauncherSettings.Favorites.SPANX,                                                             
 559 -                    LauncherSettings.Favorites.SPANY,                                                             
 560 -                    LauncherSettings.Favorites.CONTAINER                                                          
 561 -                 },                                                                                               
 562 -                 "container=?",                                                                                   
 563 -                 new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },                 
 564 -                 null);                                                                                           
 565 -                                                                                                                  
 566 -        final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 567 -        final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 568 -        final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 569 -        final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 570 -        final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 571 -        LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();                    
 572 -        try {                                                                                                     
 573 -            while (c.moveToNext()) {                                                                              
 574 -                Rect rect = new Rect();                                                                           
 575 -                rect.left = c.getInt(cellXIndex);                                                                 
 576 -                rect.top = c.getInt(cellYIndex);                                                                  
 577 -                rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                                       
 578 -                rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                                       
 579 -                                                                                                                  
 580 -                long screenId = c.getInt(screenIndex);                                                            
 581 -                ArrayList<Rect> items = screenItems.get(screenId);                                                
 582 -                if (items == null) {                                                                              
 583 -                    items = new ArrayList<Rect>();                                                                
 584 -                    screenItems.put(screenId, items);                                                             
 585 -                }                                                                                                 
 586 -                items.add(rect);                                                                                  
 587 -            }                                                                                                     
 588 -        } catch (Exception e) {                                                                                   
 589 -            screenItems.clear();                                                                                  
 590 -        } finally {                                                                                               
 591 -            c.close();                                                                                            
 592 +        LongSparseArray<ArrayList<ItemInfo>> screenItems = new LongSparseArray<>();                               
 593 +                                                                                                                  
 594 +        // Use sBgItemsIdMap as all the items are already loaded.                                                 
 595 +        assertWorkspaceLoaded();                                                                                  
 596 +        synchronized (sBgLock) {                                                                                  
 597 +            for (ItemInfo info : sBgItemsIdMap) {                                                                 
 598 +                if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
 599 +                    ArrayList<ItemInfo> items = screenItems.get(info.screenId);                                   
 600 +                    if (items == null) {                                                                          
 601 +                        items = new ArrayList<>();                                                                
 602 +                        screenItems.put(info.screenId, items);                                                    
 603 +                    }                                                                                             
 604 +                    items.add(info);                                                                              
 605 +                }                                                                                                 
 606 +            }                                                                                                     
 607          }                                                                                                         
 608                                                                                                                    
 609          // Find appropriate space for the item.                                                                   
 610          long screenId = 0;                                                                                        
 611          int[] cordinates = new int[2];                                                                            
 612          boolean found = false;                                                                                    
 613                                                                                                                    
 614          int screenCount = workspaceScreens.size();                                                                
 615          // First check the preferred screen.                                                                      
 616 -        int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                              
 617 +        int preferredScreenIndex = workspaceScreens.isEmpty() ? 0 : 1;                                            
 618          if (preferredScreenIndex < screenCount) {                                                                 
 619              screenId = workspaceScreens.get(preferredScreenIndex);                                                
 620              found = findNextAvailableIconSpaceInScreen(                                                           
 621                      screenItems.get(screenId), cordinates, spanX, spanY);                                         
 622          }                                                                                                         
 623                                                                                                                    
 624          if (!found) {                                                                                             
 625 -            // Search on any of the screens.                                                                      
 626 -            for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                              
 627 +            // Search on any of the screens starting from the first screen.                                       
 628 +            for (int screen = 1; screen < screenCount; screen++) {                                                
 629                  screenId = workspaceScreens.get(screen);                                                          
 630                  if (findNextAvailableIconSpaceInScreen(                                                           
 631                          screenItems.get(screenId), cordinates, spanX, spanY)) {                                   
 632                      // We found a space for it                                                                    
 633                      found = true;                                                                                 
 634                      break;                                                                                        
 635                  }                                                                                                 
 636              }                                                                                                     
 637          }                                                                                                         
 638                                                                                                                    
 639          if (!found) {                                                                                             
 640              // Still no position found. Add a new screen to the end.                                              
 641              screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                              
 642                                                                                                                    
 643              // Save the screen id for binding in the workspace                                                    
 644              workspaceScreens.add(screenId);                                                                       
 645              addedWorkspaceScreensFinal.add(screenId);                                                             
 646                                                                                                                    
 647              // If we still can't find an empty space, then God help us all!!!                                     
 648              if (!findNextAvailableIconSpaceInScreen(                                                              
 649                      screenItems.get(screenId), cordinates, spanX, spanY)) {                                       
 650                  throw new RuntimeException("Can't find space to add the item");                                   
 651              }                                                                                                     
 652          }                                                                                                         
 653          return Pair.create(screenId, cordinates);                                                                 
 654      }                                                                                                             
 655                                                                                                                    
 656      /**                                                                                                           
 657       * Adds the provided items to the workspace.                                                                  
 658 -     * @param preferredScreen the screen where we should try to add the app first                                 
 659 -     * @param fallbackStartScreen the screen to start search for empty space if                                   
 660 -     * preferredScreen is not available.                                                                          
 661       */                                                                                                           
 662 -    public void addAndBindPendingItem(                                                                            
 663 -            final Context context,                                                                                
 664 -            final PendingAddItemInfo addInfo,                                                                     
 665 -            final ScreenPosProvider preferredScreen,                                                              
 666 -            final int fallbackStartScreen) {                                                                      
 667 -        final Callbacks callbacks = getCallback();                                                                
 668 -        // Process the newly added applications and add them to the database first                                
 669 -        Runnable r = new Runnable() {                                                                             
 670 -            public void run() {                                                                                   
 671 -                final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 672 -                                                                                                                  
 673 -                ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 674 -                TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 675 -                for (Integer i : orderedScreens.keySet()) {                                                       
 676 -                    long screenId = orderedScreens.get(i);                                                        
 677 -                    workspaceScreens.add(screenId);                                                               
 678 -                }                                                                                                 
 679 -                                                                                                                  
 680 -                // Find appropriate space for the item.                                                           
 681 -                Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                             
 682 -                        fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                        
 683 -                        addInfo.spanX,                                                                            
 684 -                        addInfo.spanY);                                                                           
 685 -                final long screenId = coords.first;                                                               
 686 -                final int[] cordinates = coords.second;                                                           
 687 -                                                                                                                  
 688 -                // Update the workspace screens                                                                   
 689 -                updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 690 -                runOnMainThread(new Runnable() {                                                                  
 691 -                    public void run() {                                                                           
 692 -                        Callbacks cb = getCallback();                                                             
 693 -                        if (callbacks == cb && cb != null) {                                                      
 694 -                            cb.bindAddScreens(addedWorkspaceScreensFinal);                                        
 695 -                            cb.bindAddPendingItem(addInfo,                                                        
 696 -                                    LauncherSettings.Favorites.CONTAINER_DESKTOP,                                 
 697 -                                    screenId, cordinates, addInfo.spanX, addInfo.spanY);                          
 698 -                        }                                                                                         
 699 -                    }                                                                                             
 700 -                });                                                                                               
 701 -            }                                                                                                     
 702 -        };                                                                                                        
 703 -        runOnWorkerThread(r);                                                                                     
 704 -    }                                                                                                             
 705 -                                                                                                                  
 706 -    /**                                                                                                           
 707 -     * Adds the provided items to the workspace.                                                                  
 708 -     * @param preferredScreen the screen where we should try to add the app first                                 
 709 -     * @param fallbackStartScreen the screen to start search for empty space if                                   
 710 -     * preferredScreen is not available.                                                                          
 711 -     */                                                                                                           
 712 -    public void addAndBindAddedWorkspaceApps(final Context context,                                               
 713 -            final ArrayList<ItemInfo> workspaceApps,                                                              
 714 -            final ScreenPosProvider preferredScreen,                                                              
 715 -            final int fallbackStartScreen,                                                                        
 716 -            final boolean allowDuplicate) {                                                                       
 717 +    public void addAndBindAddedWorkspaceItems(final Context context,                                              
 718 +            final ArrayList<? extends ItemInfo> workspaceApps) {                                                  
 719          final Callbacks callbacks = getCallback();                                                                
 720          if (workspaceApps.isEmpty()) {                                                                            
 721              return;                                                                                               
 722          }                                                                                                         
 723          // Process the newly added applications and add them to the database first                                
 724          Runnable r = new Runnable() {                                                                             
 725              public void run() {                                                                                   
 726                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 727                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 728                                                                                                                    
 729                  // Get the list of workspace screens.  We need to append to this list and                         
 730                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 731                  // called.                                                                                        
 732 -                ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 733 -                TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 734 -                for (Integer i : orderedScreens.keySet()) {                                                       
 735 -                    long screenId = orderedScreens.get(i);                                                        
 736 -                    workspaceScreens.add(screenId);                                                               
 737 -                }                                                                                                 
 738 -                                                                                                                  
 739 +                ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                               
 740                  synchronized(sBgLock) {                                                                           
 741                      for (ItemInfo item : workspaceApps) {                                                         
 742 -                        if (!allowDuplicate) {                                                                    
 743 +                        if (item instanceof ShortcutInfo) {                                                       
 744                              // Short-circuit this logic if the icon exists somewhere on the workspace             
 745 -                            if (shortcutExists(context, item.title.toString(),                                    
 746 -                                    item.getIntent(), item.user)) {                                               
 747 +                            if (shortcutExists(context, item.getIntent(), item.user)) {                           
 748                                  continue;                                                                         
 749                              }                                                                                     
 750                          }                                                                                         
 751                                                                                                                    
 752                          // Find appropriate space for the item.                                                   
 753 -                        Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                     
 754 -                                fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                
 755 +                        Pair<Long, int[]> coords = findSpaceForItem(context,                                      
 756 +                                workspaceScreens, addedWorkspaceScreensFinal,                                     
 757                                  1, 1);                                                                            
 758                          long screenId = coords.first;                                                             
 759                          int[] cordinates = coords.second;                                                         
 760                                                                                                                    
 761 -                        ShortcutInfo shortcutInfo;                                                                
 762 -                        if (item instanceof ShortcutInfo) {                                                       
 763 -                            shortcutInfo = (ShortcutInfo) item;                                                   
 764 +                        ItemInfo itemInfo;                                                                        
 765 +                        if (item instanceof ShortcutInfo || item instanceof FolderInfo) {                         
 766 +                            itemInfo = item;                                                                      
 767                          } else if (item instanceof AppInfo) {                                                     
 768 -                            shortcutInfo = ((AppInfo) item).makeShortcut();                                       
 769 +                            itemInfo = ((AppInfo) item).makeShortcut();                                           
 770                          } else {                                                                                  
 771                              throw new RuntimeException("Unexpected info type");                                   
 772                          }                                                                                         
 773                                                                                                                    
 774                          // Add the shortcut to the db                                                             
 775 -                        addItemToDatabase(context, shortcutInfo,                                                  
 776 +                        addItemToDatabase(context, itemInfo,                                                      
 777                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 778 -                                screenId, cordinates[0], cordinates[1], false);                                   
 779 +                                screenId, cordinates[0], cordinates[1]);                                          
 780                          // Save the ShortcutInfo for binding in the workspace                                     
 781 -                        addedShortcutsFinal.add(shortcutInfo);                                                    
 782 +                        addedShortcutsFinal.add(itemInfo);                                                        
 783                      }                                                                                             
 784                  }                                                                                                 
 785                                                                                                                    
 786                  // Update the workspace screens                                                                   
 787                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 788                                                                                                                    
 789                  if (!addedShortcutsFinal.isEmpty()) {                                                             
 790                      runOnMainThread(new Runnable() {                                                              
 791                          public void run() {                                                                       
 792                              Callbacks cb = getCallback();                                                         
 793                              if (callbacks == cb && cb != null) {                                                  
 794                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 795                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 796                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 797                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 798                                      long lastScreenId = info.screenId;                                            
 799                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 800                                          if (i.screenId == lastScreenId) {                                         
 801                                              addAnimated.add(i);                                                   
 802                                          } else {                                                                  
 803                                              addNotAnimated.add(i);                                                
 804                                          }                                                                         
 805                                      }                                                                             
 806                                  }                                                                                 
 807                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 808                                          addNotAnimated, addAnimated, null);                                       
 809                              }                                                                                     
 810                          }                                                                                         
 811                      });                                                                                           
 812                  }                                                                                                 
 813              }                                                                                                     
 814          };                                                                                                        
 815          runOnWorkerThread(r);                                                                                     
 816      }                                                                                                             
 817                                                                                                                    
 818 -    public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    
 819 +    private void unbindItemInfosAndClearQueuedBindRunnables() {                                                   
 820          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 821              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 822                      "main thread");                                                                               
 823          }                                                                                                         
 824                                                                                                                    
 825          // Clear any deferred bind runnables                                                                      
 826          synchronized (mDeferredBindRunnables) {                                                                   
 827              mDeferredBindRunnables.clear();                                                                       
 828          }                                                                                                         
 829 -        // Remove any queued bind runnables                                                                       
 830 -        mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          
 831 +                                                                                                                  
 832 +        // Remove any queued UI runnables                                                                         
 833 +        mHandler.cancelAll();                                                                                     
 834          // Unbind all the workspace items                                                                         
 835          unbindWorkspaceItemsOnMainThread();                                                                       
 836      }                                                                                                             
 837                                                                                                                    
 838      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 839      void unbindWorkspaceItemsOnMainThread() {                                                                     
 840          // Ensure that we don't use the same workspace items data structure on the main thread                    
 841          // by making a copy of workspace items first.                                                             
 842 -        final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 843 -        final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      
 844 +        final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();                                           
 845          synchronized (sBgLock) {                                                                                  
 846 -            tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 847 -            tmpAppWidgets.addAll(sBgAppWidgets);                                                                  
 848 +            tmpItems.addAll(sBgWorkspaceItems);                                                                   
 849 +            tmpItems.addAll(sBgAppWidgets);                                                                       
 850          }                                                                                                         
 851          Runnable r = new Runnable() {                                                                             
 852                  @Override                                                                                         
 853                  public void run() {                                                                               
 854 -                   for (ItemInfo item : tmpWorkspaceItems) {                                                      
 855 -                       item.unbind();                                                                             
 856 -                   }                                                                                              
 857 -                   for (ItemInfo item : tmpAppWidgets) {                                                          
 858 +                   for (ItemInfo item : tmpItems) {                                                               
 859                         item.unbind();                                                                             
 860                     }                                                                                              
 861                  }                                                                                                 
 862              };                                                                                                    
 863          runOnMainThread(r);                                                                                       
 864      }                                                                                                             
 865                                                                                                                    
 866      /**                                                                                                           
 867       * Adds an item to the DB if it was not created previously, or move it to a new                               
 868       * <container, screen, cellX, cellY>                                                                          
 869       */                                                                                                           
 870      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 871              long screenId, int cellX, int cellY) {                                                                
 872          if (item.container == ItemInfo.NO_ID) {                                                                   
 873              // From all apps                                                                                      
 874 -            addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           
 875 +            addItemToDatabase(context, item, container, screenId, cellX, cellY);                                  
 876          } else {                                                                                                  
 877              // From somewhere else                                                                                
 878              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 879          }                                                                                                         
 880      }                                                                                                             
 881                                                                                                                    
 882      static void checkItemInfoLocked(                                                                              
 883              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 884          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 885          if (modelItem != null && item != modelItem) {                                                             
 886              // check all the data is consistent                                                                   
 887              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 888                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 889                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 890                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 891                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 892                          modelShortcut.id == shortcut.id &&                                                        
 893                          modelShortcut.itemType == shortcut.itemType &&                                            
 894                          modelShortcut.container == shortcut.container &&                                          
 895                          modelShortcut.screenId == shortcut.screenId &&                                            
 896                          modelShortcut.cellX == shortcut.cellX &&                                                  
 897                          modelShortcut.cellY == shortcut.cellY &&                                                  
 898                          modelShortcut.spanX == shortcut.spanX &&                                                  
 899                          modelShortcut.spanY == shortcut.spanY &&                                                  
 900                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 901                          (modelShortcut.dropPos != null &&                                                         
 902                                  shortcut.dropPos != null &&                                                       
 903                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 904                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 905                      // For all intents and purposes, this is the same object                                      
 906                      return;                                                                                       
 907                  }                                                                                                 
 908              }                                                                                                     
 909                                                                                                                    
 910              // the modelItem needs to match up perfectly with item if our model is                                
 911              // to be consistent with the database-- for now, just require                                         
 912              // modelItem == item or the equality check above                                                      
 913              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 914                      "modelItem: " +                                                                               
 915                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 916                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 917              RuntimeException e = new RuntimeException(msg);                                                       
 918              if (stackTrace != null) {                                                                             
 919                  e.setStackTrace(stackTrace);                                                                      
 920              }                                                                                                     
 921              throw e;                                                                                              
 922          }                                                                                                         
 923      }                                                                                                             
 924                                                                                                                    
 925      static void checkItemInfo(final ItemInfo item) {                                                              
 926          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 927          final long itemId = item.id;                                                                              
 928          Runnable r = new Runnable() {                                                                             
 929              public void run() {                                                                                   
 930                  synchronized (sBgLock) {                                                                          
 931                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 932                  }                                                                                                 
 933              }                                                                                                     
 934          };                                                                                                        
 935          runOnWorkerThread(r);                                                                                     
 936      }                                                                                                             
 937                                                                                                                    
 938      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 939              final ItemInfo item, final String callingFunction) {                                                  
 940          final long itemId = item.id;                                                                              
 941 -        final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  
 942 +        final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                                         
 943          final ContentResolver cr = context.getContentResolver();                                                  
 944                                                                                                                    
 945          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 946          Runnable r = new Runnable() {                                                                             
 947              public void run() {                                                                                   
 948                  cr.update(uri, values, null, null);                                                               
 949                  updateItemArrays(item, itemId, stackTrace);                                                       
 950              }                                                                                                     
 951          };                                                                                                        
 952          runOnWorkerThread(r);                                                                                     
 953      }                                                                                                             
 954                                                                                                                    
 955      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 956              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 957          final ContentResolver cr = context.getContentResolver();                                                  
 958                                                                                                                    
 959          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 960          Runnable r = new Runnable() {                                                                             
 961              public void run() {                                                                                   
 962                  ArrayList<ContentProviderOperation> ops =                                                         
 963                          new ArrayList<ContentProviderOperation>();                                                
 964                  int count = items.size();                                                                         
 965                  for (int i = 0; i < count; i++) {                                                                 
 966                      ItemInfo item = items.get(i);                                                                 
 967                      final long itemId = item.id;                                                                  
 968 -                    final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      
 969 +                    final Uri uri = LauncherSettings.Favorites.getContentUri(itemId);                             
 970                      ContentValues values = valuesList.get(i);                                                     
 971                                                                                                                    
 972                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 973                      updateItemArrays(item, itemId, stackTrace);                                                   
 974                                                                                                                    
 975                  }                                                                                                 
 976                  try {                                                                                             
 977                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 978                  } catch (Exception e) {                                                                           
 979                      e.printStackTrace();                                                                          
 980                  }                                                                                                 
 981              }                                                                                                     
 982          };                                                                                                        
 983          runOnWorkerThread(r);                                                                                     
 984      }                                                                                                             
 985                                                                                                                    
 986      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 987          // Lock on mBgLock *after* the db operation                                                               
 988          synchronized (sBgLock) {                                                                                  
 989              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 990                                                                                                                    
 991              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 992                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 993                  // Item is in a folder, make sure this folder exists                                              
 994                  if (!sBgFolders.containsKey(item.container)) {                                                    
 995                      // An items container is being set to a that of an item which is not in                       
 996                      // the list of Folders.                                                                       
 997                      String msg = "item: " + item + " container being set to: " +                                  
 998                              item.container + ", not in the list of folders";                                      
 999                      Log.e(TAG, msg);                                                                              
1000                  }                                                                                                 
1001              }                                                                                                     
1002                                                                                                                    
1003              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
1004              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
1005              // that are on the desktop, as appropriate                                                            
1006              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
1007              if (modelItem != null &&                                                                              
1008                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
1009                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
1010                  switch (modelItem.itemType) {                                                                     
1011                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
1012                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
1013                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
1014                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
1015                              sBgWorkspaceItems.add(modelItem);                                                     
1016                          }                                                                                         
1017                          break;                                                                                    
1018                      default:                                                                                      
1019                          break;                                                                                    
1020                  }                                                                                                 
1021              } else {                                                                                              
1022                  sBgWorkspaceItems.remove(modelItem);                                                              
1023              }                                                                                                     
1024          }                                                                                                         
1025      }                                                                                                             
1026                                                                                                                    
1027      /**                                                                                                           
1028       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
1029       */                                                                                                           
1030 -    static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    
1031 +    public static void moveItemInDatabase(Context context, final ItemInfo item, final long container,             
1032              final long screenId, final int cellX, final int cellY) {                                              
1033          item.container = container;                                                                               
1034          item.cellX = cellX;                                                                                       
1035          item.cellY = cellY;                                                                                       
1036                                                                                                                    
1037          // We store hotseat items in canonical form which is this orientation invariant position                  
1038          // in the hotseat                                                                                         
1039          if (context instanceof Launcher && screenId < 0 &&                                                        
1040                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1041              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1042          } else {                                                                                                  
1043              item.screenId = screenId;                                                                             
1044          }                                                                                                         
1045                                                                                                                    
1046          final ContentValues values = new ContentValues();                                                         
1047          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
1048          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
1049          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
1050          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
1051          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
1052                                                                                                                    
1053          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
1054      }                                                                                                             
1055                                                                                                                    
1056      /**                                                                                                           
1057       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
1058       * cellX, cellY have already been updated on the ItemInfos.                                                   
1059       */                                                                                                           
1060      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
1061              final long container, final int screen) {                                                             
1062                                                                                                                    
1063          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
1064          int count = items.size();                                                                                 
1065                                                                                                                    
1066          for (int i = 0; i < count; i++) {                                                                         
1067              ItemInfo item = items.get(i);                                                                         
1068              item.container = container;                                                                           
1069                                                                                                                    
1070              // We store hotseat items in canonical form which is this orientation invariant position              
1071              // in the hotseat                                                                                     
1072              if (context instanceof Launcher && screen < 0 &&                                                      
1073                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
1074                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
1075                          item.cellY);                                                                              
1076              } else {                                                                                              
1077                  item.screenId = screen;                                                                           
1078              }                                                                                                     
1079                                                                                                                    
1080              final ContentValues values = new ContentValues();                                                     
1081              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
1082              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
1083              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
1084              values.put(LauncherSettings.Favorites.RANK, item.rank);                                               
1085              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
1086                                                                                                                    
1087              contentValues.add(values);                                                                            
1088          }                                                                                                         
1089          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
1090      }                                                                                                             
1091                                                                                                                    
1092      /**                                                                                                           
1093       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
1094       */                                                                                                           
1095      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
1096              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
1097          item.container = container;                                                                               
1098          item.cellX = cellX;                                                                                       
1099          item.cellY = cellY;                                                                                       
1100          item.spanX = spanX;                                                                                       
1101          item.spanY = spanY;                                                                                       
1102                                                                                                                    
1103          // We store hotseat items in canonical form which is this orientation invariant position                  
1104          // in the hotseat                                                                                         
1105          if (context instanceof Launcher && screenId < 0 &&                                                        
1106                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1107              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1108          } else {                                                                                                  
1109              item.screenId = screenId;                                                                             
1110          }                                                                                                         
1111                                                                                                                    
1112          final ContentValues values = new ContentValues();                                                         
1113          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
1114          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
1115          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
1116          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
1117          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
1118          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
1119          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
1120                                                                                                                    
1121          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
1122      }                                                                                                             
1123                                                                                                                    
1124      /**                                                                                                           
1125       * Update an item to the database in a specified container.                                                   
1126       */                                                                                                           
1127 -    static void updateItemInDatabase(Context context, final ItemInfo item) {                                      
1128 +    public static void updateItemInDatabase(Context context, final ItemInfo item) {                               
1129          final ContentValues values = new ContentValues();                                                         
1130          item.onAddToDatabase(context, values);                                                                    
1131          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
1132      }                                                                                                             
1133                                                                                                                    
1134 +    private void assertWorkspaceLoaded() {                                                                        
1135 +        if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) {            
1136 +            throw new RuntimeException("Trying to add shortcut while loader is running");                         
1137 +        }                                                                                                         
1138 +    }                                                                                                             
1139 +                                                                                                                  
1140      /**                                                                                                           
1141 -     * Returns true if the shortcuts already exists in the database.                                              
1142 -     * we identify a shortcut by its title and intent.                                                            
1143 +     * Returns true if the shortcuts already exists on the workspace. This must be called after                   
1144 +     * the workspace has been loaded. We identify a shortcut by its intent.                                       
1145       */                                                                                                           
1146 -    static boolean shortcutExists(Context context, String title, Intent intent,                                   
1147 -            UserHandleCompat user) {                                                                              
1148 -        final ContentResolver cr = context.getContentResolver();                                                  
1149 -        final Intent intentWithPkg, intentWithoutPkg;                                                             
1150 -                                                                                                                  
1151 +    @Thunk boolean shortcutExists(Context context, Intent intent, UserHandleCompat user) {                        
1152 +        assertWorkspaceLoaded();                                                                                  
1153 +        final String intentWithPkg, intentWithoutPkg;                                                             
1154          if (intent.getComponent() != null) {                                                                      
1155              // If component is not null, an intent with null package will produce                                 
1156              // the same result and should also be a match.                                                        
1157 +            String packageName = intent.getComponent().getPackageName();                                          
1158              if (intent.getPackage() != null) {                                                                    
1159 -                intentWithPkg = intent;                                                                           
1160 -                intentWithoutPkg = new Intent(intent).setPackage(null);                                           
1161 +                intentWithPkg = intent.toUri(0);                                                                  
1162 +                intentWithoutPkg = new Intent(intent).setPackage(null).toUri(0);                                  
1163              } else {                                                                                              
1164 -                intentWithPkg = new Intent(intent).setPackage(                                                    
1165 -                        intent.getComponent().getPackageName());                                                  
1166 -                intentWithoutPkg = intent;                                                                        
1167 +                intentWithPkg = new Intent(intent).setPackage(packageName).toUri(0);                              
1168 +                intentWithoutPkg = intent.toUri(0);                                                               
1169              }                                                                                                     
1170          } else {                                                                                                  
1171 -            intentWithPkg = intent;                                                                               
1172 -            intentWithoutPkg = intent;                                                                            
1173 -        }                                                                                                         
1174 -        String userSerial = Long.toString(UserManagerCompat.getInstance(context)                                  
1175 -                .getSerialNumberForUser(user));                                                                   
1176 -        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
1177 -            new String[] { "title", "intent", "profileId" },                                                      
1178 -            "title=? and (intent=? or intent=?) and profileId=?",                                                 
1179 -            new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },                
1180 -            null);                                                                                                
1181 -        try {                                                                                                     
1182 -            return c.moveToFirst();                                                                               
1183 -        } finally {                                                                                               
1184 -            c.close();                                                                                            
1185 -        }                                                                                                         
1186 +            intentWithPkg = intent.toUri(0);                                                                      
1187 +            intentWithoutPkg = intent.toUri(0);                                                                   
1188 +        }                                                                                                         
1189 +                                                                                                                  
1190 +        synchronized (sBgLock) {                                                                                  
1191 +            for (ItemInfo item : sBgItemsIdMap) {                                                                 
1192 +                if (item instanceof ShortcutInfo) {                                                               
1193 +                    ShortcutInfo info = (ShortcutInfo) item;                                                      
1194 +                    Intent targetIntent = info.promisedIntent == null                                             
1195 +                            ? info.intent : info.promisedIntent;                                                  
1196 +                    if (targetIntent != null && info.user.equals(user)) {                                         
1197 +                        String s = targetIntent.toUri(0);                                                         
1198 +                        if (intentWithPkg.equals(s) || intentWithoutPkg.equals(s)) {                              
1199 +                            return true;                                                                          
1200 +                        }                                                                                         
1201 +                    }                                                                                             
1202 +                }                                                                                                 
1203 +            }                                                                                                     
1204 +        }                                                                                                         
1205 +        return false;                                                                                             
1206      }                                                                                                             
1207                                                                                                                    
1208      /**                                                                                                           
1209       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
1210       */                                                                                                           
1211 -    FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     
1212 +    FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {                     
1213          final ContentResolver cr = context.getContentResolver();                                                  
1214          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
1215                  "_id=? and (itemType=? or itemType=?)",                                                           
1216                  new String[] { String.valueOf(id),                                                                
1217                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
1218                                                                                                                    
1219          try {                                                                                                     
1220              if (c.moveToFirst()) {                                                                                
1221                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
1222                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
1223                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
1224                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
1225                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
1226                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 
1227 +                final int optionsIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.OPTIONS);             
1228                                                                                                                    
1229                  FolderInfo folderInfo = null;                                                                     
1230                  switch (c.getInt(itemTypeIndex)) {                                                                
1231                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
1232                          folderInfo = findOrMakeFolder(folderList, id);                                            
1233                          break;                                                                                    
1234                  }                                                                                                 
1235                                                                                                                    
1236 +                // Do not trim the folder label, as is was set by the user.                                       
1237                  folderInfo.title = c.getString(titleIndex);                                                       
1238                  folderInfo.id = id;                                                                               
1239                  folderInfo.container = c.getInt(containerIndex);                                                  
1240                  folderInfo.screenId = c.getInt(screenIndex);                                                      
1241                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
1242                  folderInfo.cellY = c.getInt(cellYIndex);                                                          
1243 +                folderInfo.options = c.getInt(optionsIndex);                                                      
1244                                                                                                                    
1245                  return folderInfo;                                                                                
1246              }                                                                                                     
1247          } finally {                                                                                               
1248              c.close();                                                                                            
1249          }                                                                                                         
1250                                                                                                                    
1251          return null;                                                                                              
1252      }                                                                                                             
1253                                                                                                                    
1254      /**                                                                                                           
1255       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
1256       * cellY fields of the item. Also assigns an ID to the item.                                                  
1257       */                                                                                                           
1258 -    static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
1259 -            final long screenId, final int cellX, final int cellY, final boolean notify) {                        
1260 +    public static void addItemToDatabase(Context context, final ItemInfo item, final long container,              
1261 +            final long screenId, final int cellX, final int cellY) {                                              
1262          item.container = container;                                                                               
1263          item.cellX = cellX;                                                                                       
1264          item.cellY = cellY;                                                                                       
1265          // We store hotseat items in canonical form which is this orientation invariant position                  
1266          // in the hotseat                                                                                         
1267          if (context instanceof Launcher && screenId < 0 &&                                                        
1268                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1269              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1270          } else {                                                                                                  
1271              item.screenId = screenId;                                                                             
1272          }                                                                                                         
1273                                                                                                                    
1274          final ContentValues values = new ContentValues();                                                         
1275          final ContentResolver cr = context.getContentResolver();                                                  
1276          item.onAddToDatabase(context, values);                                                                    
1277                                                                                                                    
1278          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
1279          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
1280                                                                                                                    
1281          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
1282          Runnable r = new Runnable() {                                                                             
1283              public void run() {                                                                                   
1284 -                cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
1285 -                        LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          
1286 +                cr.insert(LauncherSettings.Favorites.CONTENT_URI, values);                                        
1287                                                                                                                    
1288                  // Lock on mBgLock *after* the db operation                                                       
1289                  synchronized (sBgLock) {                                                                          
1290                      checkItemInfoLocked(item.id, item, stackTrace);                                               
1291                      sBgItemsIdMap.put(item.id, item);                                                             
1292                      switch (item.itemType) {                                                                      
1293                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
1294                              sBgFolders.put(item.id, (FolderInfo) item);                                           
1295                              // Fall through                                                                       
1296                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
1297                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
1298                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
1299                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
1300                                  sBgWorkspaceItems.add(item);                                                      
1301                              } else {                                                                              
1302                                  if (!sBgFolders.containsKey(item.container)) {                                    
1303                                      // Adding an item to a folder that doesn't exist.                             
1304                                      String msg = "adding item: " + item + " to a folder that " +                  
1305                                              " doesn't exist";                                                     
1306                                      Log.e(TAG, msg);                                                              
1307                                  }                                                                                 
1308                              }                                                                                     
1309                              break;                                                                                
1310                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
1311                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
1312                              break;                                                                                
1313                      }                                                                                             
1314                  }                                                                                                 
1315              }                                                                                                     
1316          };                                                                                                        
1317          runOnWorkerThread(r);                                                                                     
1318      }                                                                                                             
1319                                                                                                                    
1320      /**                                                                                                           
1321       * Creates a new unique child id, for a given cell span across all layouts.                                   
1322       */                                                                                                           
1323      static int getCellLayoutChildId(                                                                              
1324              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
1325          return (((int) container & 0xFF) << 24)                                                                   
1326                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
1327      }                                                                                                             
1328                                                                                                                    
1329      private static ArrayList<ItemInfo> getItemsByPackageName(                                                     
1330              final String pn, final UserHandleCompat user) {                                                       
1331          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
1332              @Override                                                                                             
1333              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
1334                  return cn.getPackageName().equals(pn) && info.user.equals(user);                                  
1335              }                                                                                                     
1336          };                                                                                                        
1337 -        return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
1338 +        return filterItemInfos(sBgItemsIdMap, filter);                                                            
1339      }                                                                                                             
1340                                                                                                                    
1341      /**                                                                                                           
1342       * Removes all the items from the database corresponding to the specified package.                            
1343       */                                                                                                           
1344      static void deletePackageFromDatabase(Context context, final String pn,                                       
1345              final UserHandleCompat user) {                                                                        
1346          deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                                        
1347      }                                                                                                             
1348                                                                                                                    
1349      /**                                                                                                           
1350       * Removes the specified item from the database                                                               
1351       * @param context                                                                                             
1352       * @param item                                                                                                
1353       */                                                                                                           
1354 -    static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    
1355 +    public static void deleteItemFromDatabase(Context context, final ItemInfo item) {                             
1356          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
1357          items.add(item);                                                                                          
1358          deleteItemsFromDatabase(context, items);                                                                  
1359      }                                                                                                             
1360                                                                                                                    
1361      /**                                                                                                           
1362       * Removes the specified items from the database                                                              
1363       * @param context                                                                                             
1364       * @param item                                                                                                
1365       */                                                                                                           
1366      static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {             
1367          final ContentResolver cr = context.getContentResolver();                                                  
1368 -                                                                                                                  
1369          Runnable r = new Runnable() {                                                                             
1370              public void run() {                                                                                   
1371                  for (ItemInfo item : items) {                                                                     
1372 -                    final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);                     
1373 +                    final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);                            
1374                      cr.delete(uri, null, null);                                                                   
1375                                                                                                                    
1376                      // Lock on mBgLock *after* the db operation                                                   
1377                      synchronized (sBgLock) {                                                                      
1378                          switch (item.itemType) {                                                                  
1379                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1380                                  sBgFolders.remove(item.id);                                                       
1381 -                                for (ItemInfo info: sBgItemsIdMap.values()) {                                     
1382 +                                for (ItemInfo info: sBgItemsIdMap) {                                              
1383                                      if (info.container == item.id) {                                              
1384                                          // We are deleting a folder which still contains items that               
1385                                          // think they are contained by that folder.                               
1386                                          String msg = "deleting a folder (" + item + ") which still " +            
1387                                                  "contains items (" + info + ")";                                  
1388                                          Log.e(TAG, msg);                                                          
1389                                      }                                                                             
1390                                  }                                                                                 
1391                                  sBgWorkspaceItems.remove(item);                                                   
1392                                  break;                                                                            
1393                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1394                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1395                                  sBgWorkspaceItems.remove(item);                                                   
1396                                  break;                                                                            
1397                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1398                                  sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                               
1399                                  break;                                                                            
1400                          }                                                                                         
1401                          sBgItemsIdMap.remove(item.id);                                                            
1402 -                        sBgDbIconCache.remove(item);                                                              
1403                      }                                                                                             
1404                  }                                                                                                 
1405              }                                                                                                     
1406          };                                                                                                        
1407          runOnWorkerThread(r);                                                                                     
1408      }                                                                                                             
1409                                                                                                                    
1410      /**                                                                                                           
1411       * Update the order of the workspace screens in the database. The array list contains                         
1412       * a list of screen ids in the order that they should appear.                                                 
1413       */                                                                                                           
1414      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1415 -        // Log to disk                                                                                            
1416 -        Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1417 -        Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1418 -                                                                                                                  
1419          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1420          final ContentResolver cr = context.getContentResolver();                                                  
1421          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1422                                                                                                                    
1423          // Remove any negative screen ids -- these aren't persisted                                               
1424          Iterator<Long> iter = screensCopy.iterator();                                                             
1425          while (iter.hasNext()) {                                                                                  
1426              long id = iter.next();                                                                                
1427              if (id < 0) {                                                                                         
1428                  iter.remove();                                                                                    
1429              }                                                                                                     
1430          }                                                                                                         
1431                                                                                                                    
1432          Runnable r = new Runnable() {                                                                             
1433              @Override                                                                                             
1434              public void run() {                                                                                   
1435                  ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();              
1436                  // Clear the table                                                                                
1437                  ops.add(ContentProviderOperation.newDelete(uri).build());                                         
1438                  int count = screensCopy.size();                                                                   
1439                  for (int i = 0; i < count; i++) {                                                                 
1440                      ContentValues v = new ContentValues();                                                        
1441                      long screenId = screensCopy.get(i);                                                           
1442                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1443                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1444                      ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());                       
1445                  }                                                                                                 
1446                                                                                                                    
1447                  try {                                                                                             
1448                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
1449                  } catch (Exception ex) {                                                                          
1450                      throw new RuntimeException(ex);                                                               
1451                  }                                                                                                 
1452                                                                                                                    
1453                  synchronized (sBgLock) {                                                                          
1454                      sBgWorkspaceScreens.clear();                                                                  
1455                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1456                  }                                                                                                 
1457              }                                                                                                     
1458          };                                                                                                        
1459          runOnWorkerThread(r);                                                                                     
1460      }                                                                                                             
1461                                                                                                                    
1462      /**                                                                                                           
1463       * Remove the contents of the specified folder from the database                                              
1464       */                                                                                                           
1465 -    static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        
1466 +    public static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                 
1467          final ContentResolver cr = context.getContentResolver();                                                  
1468                                                                                                                    
1469          Runnable r = new Runnable() {                                                                             
1470              public void run() {                                                                                   
1471 -                cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  
1472 +                cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);                         
1473                  // Lock on mBgLock *after* the db operation                                                       
1474                  synchronized (sBgLock) {                                                                          
1475                      sBgItemsIdMap.remove(info.id);                                                                
1476                      sBgFolders.remove(info.id);                                                                   
1477 -                    sBgDbIconCache.remove(info);                                                                  
1478                      sBgWorkspaceItems.remove(info);                                                               
1479                  }                                                                                                 
1480                                                                                                                    
1481 -                cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 
1482 +                cr.delete(LauncherSettings.Favorites.CONTENT_URI,                                                 
1483                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1484                  // Lock on mBgLock *after* the db operation                                                       
1485                  synchronized (sBgLock) {                                                                          
1486                      for (ItemInfo childInfo : info.contents) {                                                    
1487                          sBgItemsIdMap.remove(childInfo.id);                                                       
1488 -                        sBgDbIconCache.remove(childInfo);                                                         
1489                      }                                                                                             
1490                  }                                                                                                 
1491              }                                                                                                     
1492          };                                                                                                        
1493          runOnWorkerThread(r);                                                                                     
1494      }                                                                                                             
1495                                                                                                                    
1496      /**                                                                                                           
1497       * Set this as the current Launcher activity object for the loader.                                           
1498       */                                                                                                           
1499      public void initialize(Callbacks callbacks) {                                                                 
1500          synchronized (mLock) {                                                                                    
1501 +            // Disconnect any of the callbacks and drawables associated with ItemInfos on the                     
1502 +            // workspace to prevent leaking Launcher activities on orientation change.                            
1503 +            unbindItemInfosAndClearQueuedBindRunnables();                                                         
1504              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1505          }                                                                                                         
1506      }                                                                                                             
1507                                                                                                                    
1508      @Override                                                                                                     
1509      public void onPackageChanged(String packageName, UserHandleCompat user) {                                     
1510          int op = PackageUpdatedTask.OP_UPDATE;                                                                    
1511          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1512                  user));                                                                                           
1513      }                                                                                                             
1514                                                                                                                    
1515      @Override                                                                                                     
1516      public void onPackageRemoved(String packageName, UserHandleCompat user) {                                     
1517          int op = PackageUpdatedTask.OP_REMOVE;                                                                    
1518          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1519                  user));                                                                                           
1520      }                                                                                                             
1521                                                                                                                    
1522      @Override                                                                                                     
1523      public void onPackageAdded(String packageName, UserHandleCompat user) {                                       
1524          int op = PackageUpdatedTask.OP_ADD;                                                                       
1525          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1526                  user));                                                                                           
1527      }                                                                                                             
1528                                                                                                                    
1529      @Override                                                                                                     
1530      public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                                 
1531              boolean replacing) {                                                                                  
1532          if (!replacing) {                                                                                         
1533              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,                 
1534                      user));                                                                                       
1535              if (mAppsCanBeOnRemoveableStorage) {                                                                  
1536                  // Only rebind if we support removable storage. It catches the                                    
1537                  // case where                                                                                     
1538                  // apps on the external sd card need to be reloaded                                               
1539                  startLoaderFromBackground();                                                                      
1540              }                                                                                                     
1541          } else {                                                                                                  
1542              // If we are replacing then just update the packages in the list                                      
1543              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                            
1544                      packageNames, user));                                                                         
1545          }                                                                                                         
1546      }                                                                                                             
1547                                                                                                                    
1548      @Override                                                                                                     
1549      public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                               
1550              boolean replacing) {                                                                                  
1551          if (!replacing) {                                                                                         
1552              enqueuePackageUpdated(new PackageUpdatedTask(                                                         
1553                      PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                              
1554                      user));                                                                                       
1555          }                                                                                                         
1556      }                                                                                                             
1557                                                                                                                    
1558      /**                                                                                                           
1559       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1560       * ACTION_PACKAGE_CHANGED.                                                                                    
1561       */                                                                                                           
1562      @Override                                                                                                     
1563      public void onReceive(Context context, Intent intent) {                                                       
1564          if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                             
1565                                                                                                                    
1566          final String action = intent.getAction();                                                                 
1567          if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                        
1568              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1569              forceReload();                                                                                        
1570 -        } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1571 -             // Check if configuration change was an mcc/mnc change which would affect app resources              
1572 -             // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1573 -             // above for ACTION_LOCALE_CHANGED                                                                   
1574 -             Configuration currentConfig = context.getResources().getConfiguration();                             
1575 -             if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1576 -                   Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1577 -                       + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1578 -                   forceReload();                                                                                 
1579 -             }                                                                                                    
1580 -             // Update previousConfig                                                                             
1581 -             mPreviousConfigMcc = currentConfig.mcc;                                                              
1582          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1583                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1584              Callbacks callbacks = getCallback();                                                                  
1585              if (callbacks != null) {                                                                              
1586                  callbacks.bindSearchablesChanged();                                                               
1587              }                                                                                                     
1588 +        } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action)                                 
1589 +                || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {                            
1590 +            forceReload();                                                                                        
1591          }                                                                                                         
1592      }                                                                                                             
1593                                                                                                                    
1594      void forceReload() {                                                                                          
1595          resetLoadedState(true, true);                                                                             
1596                                                                                                                    
1597          // Do this here because if the launcher activity is running it will be restarted.                         
1598          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1599          // to reload.                                                                                             
1600          startLoaderFromBackground();                                                                              
1601      }                                                                                                             
1602                                                                                                                    
1603      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1604          synchronized (mLock) {                                                                                    
1605              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1606              // mWorkspaceLoaded to true later                                                                     
1607              stopLoaderLocked();                                                                                   
1608              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1609              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1610          }                                                                                                         
1611      }                                                                                                             
1612                                                                                                                    
1613      /**                                                                                                           
1614       * When the launcher is in the background, it's possible for it to miss paired                                
1615       * configuration changes.  So whenever we trigger the loader from the background                              
1616       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1617       * of doing it now.                                                                                           
1618       */                                                                                                           
1619      public void startLoaderFromBackground() {                                                                     
1620          boolean runLoader = false;                                                                                
1621          Callbacks callbacks = getCallback();                                                                      
1622          if (callbacks != null) {                                                                                  
1623              // Only actually run the loader if they're not paused.                                                
1624              if (!callbacks.setLoadOnResume()) {                                                                   
1625                  runLoader = true;                                                                                 
1626              }                                                                                                     
1627          }                                                                                                         
1628          if (runLoader) {                                                                                          
1629 -            startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1630 -        }                                                                                                         
1631 -    }                                                                                                             
1632 -                                                                                                                  
1633 -    // If there is already a loader task running, tell it to stop.                                                
1634 -    // returns true if isLaunching() was true on the old task                                                     
1635 -    private boolean stopLoaderLocked() {                                                                          
1636 -        boolean isLaunching = false;                                                                              
1637 +            startLoader(PagedView.INVALID_RESTORE_PAGE);                                                          
1638 +        }                                                                                                         
1639 +    }                                                                                                             
1640 +                                                                                                                  
1641 +    /**                                                                                                           
1642 +     * If there is already a loader task running, tell it to stop.                                                
1643 +     */                                                                                                           
1644 +    private void stopLoaderLocked() {                                                                             
1645          LoaderTask oldTask = mLoaderTask;                                                                         
1646          if (oldTask != null) {                                                                                    
1647 -            if (oldTask.isLaunching()) {                                                                          
1648 -                isLaunching = true;                                                                               
1649 -            }                                                                                                     
1650              oldTask.stopLocked();                                                                                 
1651          }                                                                                                         
1652 -        return isLaunching;                                                                                       
1653      }                                                                                                             
1654                                                                                                                    
1655      public boolean isCurrentCallbacks(Callbacks callbacks) {                                                      
1656          return (mCallbacks != null && mCallbacks.get() == callbacks);                                             
1657      }                                                                                                             
1658                                                                                                                    
1659 -    public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1660 -        startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1661 -    }                                                                                                             
1662 -                                                                                                                  
1663 -    public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        
1664 +    public void startLoader(int synchronousBindPage) {                                                            
1665 +        startLoader(synchronousBindPage, LOADER_FLAG_NONE);                                                       
1666 +    }                                                                                                             
1667 +                                                                                                                  
1668 +    public void startLoader(int synchronousBindPage, int loadFlags) {                                             
1669 +        // Enable queue before starting loader. It will get disabled in Launcher#finishBindingItems               
1670 +        InstallShortcutReceiver.enableInstallQueue();                                                             
1671          synchronized (mLock) {                                                                                    
1672 -            if (DEBUG_LOADERS) {                                                                                  
1673 -                Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1674 -            }                                                                                                     
1675 -                                                                                                                  
1676              // Clear any deferred bind-runnables from the synchronized load process                               
1677              // We must do this before any loading/binding is scheduled below.                                     
1678              synchronized (mDeferredBindRunnables) {                                                               
1679                  mDeferredBindRunnables.clear();                                                                   
1680              }                                                                                                     
1681                                                                                                                    
1682              // Don't bother to start the thread if we know it's not going to do anything                          
1683              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1684                  // If there is already one running, tell it to stop.                                              
1685 -                // also, don't downgrade isLaunching if we're already running                                     
1686 -                isLaunching = isLaunching || stopLoaderLocked();                                                  
1687 -                mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          
1688 +                stopLoaderLocked();                                                                               
1689 +                mLoaderTask = new LoaderTask(mApp.getContext(), loadFlags);                                       
1690                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1691 -                        && mAllAppsLoaded && mWorkspaceLoaded) {                                                  
1692 +                        && mAllAppsLoaded && mWorkspaceLoaded && !mIsLoaderTaskRunning) {                         
1693                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1694                  } else {                                                                                          
1695                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1696                      sWorker.post(mLoaderTask);                                                                    
1697                  }                                                                                                 
1698              }                                                                                                     
1699          }                                                                                                         
1700      }                                                                                                             
1701                                                                                                                    
1702      void bindRemainingSynchronousPages() {                                                                        
1703          // Post the remaining side pages to be loaded                                                             
1704          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1705              Runnable[] deferredBindRunnables = null;                                                              
1706              synchronized (mDeferredBindRunnables) {                                                               
1707                  deferredBindRunnables = mDeferredBindRunnables.toArray(                                           
1708                          new Runnable[mDeferredBindRunnables.size()]);                                             
1709                  mDeferredBindRunnables.clear();                                                                   
1710              }                                                                                                     
1711              for (final Runnable r : deferredBindRunnables) {                                                      
1712 -                mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   
1713 +                mHandler.post(r);                                                                                 
1714 +            }                                                                                                     
1715 +        }                                                                                                         
1716 +                                                                                                                  
1717 +        // Run all the bind complete runnables after workspace is bound.                                          
1718 +        if (!mBindCompleteRunnables.isEmpty()) {                                                                  
1719 +            synchronized (mBindCompleteRunnables) {                                                               
1720 +                for (final Runnable r : mBindCompleteRunnables) {                                                 
1721 +                    runOnWorkerThread(r);                                                                         
1722 +                }                                                                                                 
1723 +                mBindCompleteRunnables.clear();                                                                   
1724              }                                                                                                     
1725          }                                                                                                         
1726      }                                                                                                             
1727                                                                                                                    
1728      public void stopLoader() {                                                                                    
1729          synchronized (mLock) {                                                                                    
1730              if (mLoaderTask != null) {                                                                            
1731                  mLoaderTask.stopLocked();                                                                         
1732              }                                                                                                     
1733          }                                                                                                         
1734      }                                                                                                             
1735                                                                                                                    
1736 -    /** Loads the workspace screens db into a map of Rank -> ScreenId */                                          
1737 -    private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                               
1738 +    /**                                                                                                           
1739 +     * Loads the workspace screen ids in an ordered list.                                                         
1740 +     */                                                                                                           
1741 +    @Thunk static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                                       
1742          final ContentResolver contentResolver = context.getContentResolver();                                     
1743          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1744 -        final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                              
1745 -        TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                                     
1746 -                                                                                                                  
1747 +                                                                                                                  
1748 +        // Get screens ordered by rank.                                                                           
1749 +        final Cursor sc = contentResolver.query(screensUri, null, null, null,                                     
1750 +                LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                                   
1751 +        ArrayList<Long> screenIds = new ArrayList<Long>();                                                        
1752          try {                                                                                                     
1753 -            final int idIndex = sc.getColumnIndexOrThrow(                                                         
1754 -                    LauncherSettings.WorkspaceScreens._ID);                                                       
1755 -            final int rankIndex = sc.getColumnIndexOrThrow(                                                       
1756 -                    LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                               
1757 +            final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);                  
1758              while (sc.moveToNext()) {                                                                             
1759                  try {                                                                                             
1760 -                    long screenId = sc.getLong(idIndex);                                                          
1761 -                    int rank = sc.getInt(rankIndex);                                                              
1762 -                    orderedScreens.put(rank, screenId);                                                           
1763 +                    screenIds.add(sc.getLong(idIndex));                                                           
1764                  } catch (Exception e) {                                                                           
1765 -                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);  
1766 +                    Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                                  
1767 +                            + " - invalid screens: " + e, true);                                                  
1768                  }                                                                                                 
1769              }                                                                                                     
1770          } finally {                                                                                               
1771              sc.close();                                                                                           
1772          }                                                                                                         
1773 -                                                                                                                  
1774 -        // Log to disk                                                                                            
1775 -        Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                                    
1776 -        ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                           
1777 -        for (Integer i : orderedScreens.keySet()) {                                                               
1778 -            orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                              
1779 -        }                                                                                                         
1780 -        Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                                       
1781 -                TextUtils.join(", ", orderedScreensPairs), true);                                                 
1782 -        return orderedScreens;                                                                                    
1783 +        return screenIds;                                                                                         
1784      }                                                                                                             
1785                                                                                                                    
1786      public boolean isAllAppsLoaded() {                                                                            
1787          return mAllAppsLoaded;                                                                                    
1788      }                                                                                                             
1789                                                                                                                    
1790      boolean isLoadingWorkspace() {                                                                                
1791          synchronized (mLock) {                                                                                    
1792              if (mLoaderTask != null) {                                                                            
1793                  return mLoaderTask.isLoadingWorkspace();                                                          
1794              }                                                                                                     
1795          }                                                                                                         
1796          return false;                                                                                             
1797      }                                                                                                             
1798                                                                                                                    
1799      /**                                                                                                           
1800       * Runnable for the thread that loads the contents of the launcher:                                           
1801       *   - workspace icons                                                                                        
1802       *   - widgets                                                                                                
1803       *   - all apps icons                                                                                         
1804       */                                                                                                           
1805      private class LoaderTask implements Runnable {                                                                
1806          private Context mContext;                                                                                 
1807 -        private boolean mIsLaunching;                                                                             
1808 -        private boolean mIsLoadingAndBindingWorkspace;                                                            
1809 +        @Thunk boolean mIsLoadingAndBindingWorkspace;                                                             
1810          private boolean mStopped;                                                                                 
1811 -        private boolean mLoadAndBindStepFinished;                                                                 
1812 +        @Thunk boolean mLoadAndBindStepFinished;                                                                  
1813          private int mFlags;                                                                                       
1814                                                                                                                    
1815 -        private HashMap<Object, CharSequence> mLabelCache;                                                        
1816 -                                                                                                                  
1817 -        LoaderTask(Context context, boolean isLaunching, int flags) {                                             
1818 +        LoaderTask(Context context, int flags) {                                                                  
1819              mContext = context;                                                                                   
1820 -            mIsLaunching = isLaunching;                                                                           
1821 -            mLabelCache = new HashMap<Object, CharSequence>();                                                    
1822              mFlags = flags;                                                                                       
1823 -        }                                                                                                         
1824 -                                                                                                                  
1825 -        boolean isLaunching() {                                                                                   
1826 -            return mIsLaunching;                                                                                  
1827          }                                                                                                         
1828                                                                                                                    
1829          boolean isLoadingWorkspace() {                                                                            
1830              return mIsLoadingAndBindingWorkspace;                                                                 
1831          }                                                                                                         
1832                                                                                                                    
1833 -        /** Returns whether this is an upgrade path */                                                            
1834 -        private boolean loadAndBindWorkspace() {                                                                  
1835 +        private void loadAndBindWorkspace() {                                                                     
1836              mIsLoadingAndBindingWorkspace = true;                                                                 
1837                                                                                                                    
1838              // Load the workspace                                                                                 
1839              if (DEBUG_LOADERS) {                                                                                  
1840                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1841              }                                                                                                     
1842                                                                                                                    
1843 -            boolean isUpgradePath = false;                                                                        
1844              if (!mWorkspaceLoaded) {                                                                              
1845 -                isUpgradePath = loadWorkspace();                                                                  
1846 +                loadWorkspace();                                                                                  
1847                  synchronized (LoaderTask.this) {                                                                  
1848                      if (mStopped) {                                                                               
1849 -                        return isUpgradePath;                                                                     
1850 +                        return;                                                                                   
1851                      }                                                                                             
1852                      mWorkspaceLoaded = true;                                                                      
1853                  }                                                                                                 
1854              }                                                                                                     
1855                                                                                                                    
1856              // Bind the workspace                                                                                 
1857 -            bindWorkspace(-1, isUpgradePath);                                                                     
1858 -            return isUpgradePath;                                                                                 
1859 +            bindWorkspace(-1);                                                                                    
1860          }                                                                                                         
1861                                                                                                                    
1862          private void waitForIdle() {                                                                              
1863              // Wait until the either we're stopped or the other threads are done.                                 
1864              // This way we don't start loading all apps until the workspace has settled                           
1865              // down.                                                                                              
1866              synchronized (LoaderTask.this) {                                                                      
1867                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1868                                                                                                                    
1869                  mHandler.postIdle(new Runnable() {                                                                
1870                          public void run() {                                                                       
1871                              synchronized (LoaderTask.this) {                                                      
1872                                  mLoadAndBindStepFinished = true;                                                  
1873                                  if (DEBUG_LOADERS) {                                                              
1874                                      Log.d(TAG, "done with previous binding step");                                
1875                                  }                                                                                 
1876                                  LoaderTask.this.notify();                                                         
1877                              }                                                                                     
1878                          }                                                                                         
1879                      });                                                                                           
1880                                                                                                                    
1881                  while (!mStopped && !mLoadAndBindStepFinished) {                                                  
1882                      try {                                                                                         
1883                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1884                          // wait no longer than 1sec at a time                                                     
1885                          this.wait(1000);                                                                          
1886                      } catch (InterruptedException ex) {                                                           
1887                          // Ignore                                                                                 
1888                      }                                                                                             
1889                  }                                                                                                 
1890                  if (DEBUG_LOADERS) {                                                                              
1891                      Log.d(TAG, "waited "                                                                          
1892                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1893                              + "ms for previous step to finish binding");                                          
1894                  }                                                                                                 
1895              }                                                                                                     
1896          }                                                                                                         
1897                                                                                                                    
1898          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1899              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1900                  // Ensure that we have a valid page index to load synchronously                                   
1901                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1902                          "valid page index");                                                                      
1903              }                                                                                                     
1904              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1905                  // Ensure that we don't try and bind a specified page when the pages have not been                
1906                  // loaded already (we should load everything asynchronously in that case)                         
1907                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1908              }                                                                                                     
1909              synchronized (mLock) {                                                                                
1910                  if (mIsLoaderTaskRunning) {                                                                       
1911                      // Ensure that we are never running the background loading at this point since                
1912                      // we also touch the background collections                                                   
1913                      throw new RuntimeException("Error! Background loading is already running");                   
1914                  }                                                                                                 
1915              }                                                                                                     
1916                                                                                                                    
1917              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1918              //      data structures, we can't allow any other thread to touch that data, but because              
1919              //      this call is synchronous, we can get away with not locking).                                  
1920                                                                                                                    
1921              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1922              // operations from the previous activity.  We need to ensure that all queued operations               
1923              // are executed before any synchronous binding work is done.                                          
1924              mHandler.flush();                                                                                     
1925                                                                                                                    
1926              // Divide the set of loaded items into those that we are binding synchronously, and                   
1927              // everything else that is to be bound normally (asynchronously).                                     
1928 -            bindWorkspace(synchronousBindPage, false);                                                            
1929 +            bindWorkspace(synchronousBindPage);                                                                   
1930              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1931              //      arise from that.                                                                              
1932              onlyBindAllApps();                                                                                    
1933          }                                                                                                         
1934                                                                                                                    
1935          public void run() {                                                                                       
1936 -            boolean isUpgrade = false;                                                                            
1937 -                                                                                                                  
1938              synchronized (mLock) {                                                                                
1939 +                if (mStopped) {                                                                                   
1940 +                    return;                                                                                       
1941 +                }                                                                                                 
1942                  mIsLoaderTaskRunning = true;                                                                      
1943              }                                                                                                     
1944              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1945              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1946              // workspace first (default).                                                                         
1947              keep_running: {                                                                                       
1948 -                // Elevate priority when Home launches for the first time to avoid                                
1949 -                // starving at boot time. Staring at a blank home is not cool.                                    
1950 -                synchronized (mLock) {                                                                            
1951 -                    if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1952 -                            (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1953 -                    android.os.Process.setThreadPriority(mIsLaunching                                             
1954 -                            ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1955 -                }                                                                                                 
1956                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1957 -                isUpgrade = loadAndBindWorkspace();                                                               
1958 +                loadAndBindWorkspace();                                                                           
1959                                                                                                                    
1960                  if (mStopped) {                                                                                   
1961                      break keep_running;                                                                           
1962                  }                                                                                                 
1963                                                                                                                    
1964 -                // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1965 -                // settled down.                                                                                  
1966 -                synchronized (mLock) {                                                                            
1967 -                    if (mIsLaunching) {                                                                           
1968 -                        if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1969 -                        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1970 -                    }                                                                                             
1971 -                }                                                                                                 
1972                  waitForIdle();                                                                                    
1973                                                                                                                    
1974                  // second step                                                                                    
1975                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1976                  loadAndBindAllApps();                                                                             
1977 -                                                                                                                  
1978 -                // Restore the default thread priority after we are done loading items                            
1979 -                synchronized (mLock) {                                                                            
1980 -                    android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1981 -                }                                                                                                 
1982 -            }                                                                                                     
1983 -                                                                                                                  
1984 -            // Update the saved icons if necessary                                                                
1985 -            if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1986 -            synchronized (sBgLock) {                                                                              
1987 -                for (Object key : sBgDbIconCache.keySet()) {                                                      
1988 -                    updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1989 -                }                                                                                                 
1990 -                sBgDbIconCache.clear();                                                                           
1991 -            }                                                                                                     
1992 -                                                                                                                  
1993 -            if (LauncherAppState.isDisableAllApps()) {                                                            
1994 -                // Ensure that all the applications that are in the system are                                    
1995 -                // represented on the home screen.                                                                
1996 -                if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                                
1997 -                    verifyApplications();                                                                         
1998 -                }                                                                                                 
1999              }                                                                                                     
2000                                                                                                                    
2001              // Clear out this reference, otherwise we end up holding it until all of the                          
2002              // callback runnables are done.                                                                       
2003              mContext = null;                                                                                      
2004                                                                                                                    
2005              synchronized (mLock) {                                                                                
2006                  // If we are still the last one to be scheduled, remove ourselves.                                
2007                  if (mLoaderTask == this) {                                                                        
2008                      mLoaderTask = null;                                                                           
2009                  }                                                                                                 
2010                  mIsLoaderTaskRunning = false;                                                                     
2011 +                mHasLoaderCompletedOnce = true;                                                                   
2012              }                                                                                                     
2013          }                                                                                                         
2014                                                                                                                    
2015          public void stopLocked() {                                                                                
2016              synchronized (LoaderTask.this) {                                                                      
2017                  mStopped = true;                                                                                  
2018                  this.notify();                                                                                    
2019              }                                                                                                     
2020          }                                                                                                         
2021                                                                                                                    
2022          /**                                                                                                       
2023           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
2024           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
2025           * object that was around when the deferred message was scheduled, and if there's                         
2026           * a new Callbacks object around then also return null.  This will save us from                           
2027           * calling onto it with data that will be ignored.                                                        
2028           */                                                                                                       
2029          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
2030              synchronized (mLock) {                                                                                
2031                  if (mStopped) {                                                                                   
2032                      return null;                                                                                  
2033                  }                                                                                                 
2034                                                                                                                    
2035                  if (mCallbacks == null) {                                                                         
2036                      return null;                                                                                  
2037                  }                                                                                                 
2038                                                                                                                    
2039                  final Callbacks callbacks = mCallbacks.get();                                                     
2040                  if (callbacks != oldCallbacks) {                                                                  
2041                      return null;                                                                                  
2042                  }                                                                                                 
2043                  if (callbacks == null) {                                                                          
2044                      Log.w(TAG, "no mCallbacks");                                                                  
2045                      return null;                                                                                  
2046                  }                                                                                                 
2047                                                                                                                    
2048                  return callbacks;                                                                                 
2049              }                                                                                                     
2050          }                                                                                                         
2051                                                                                                                    
2052 -        private void verifyApplications() {                                                                       
2053 -            final Context context = mApp.getContext();                                                            
2054 -                                                                                                                  
2055 -            // Cross reference all the applications in our apps list with items in the workspace                  
2056 -            ArrayList<ItemInfo> tmpInfos;                                                                         
2057 -            ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
2058 -            synchronized (sBgLock) {                                                                              
2059 -                for (AppInfo app : mBgAllAppsList.data) {                                                         
2060 -                    tmpInfos = getItemInfoForComponentName(app.componentName, app.user);                          
2061 -                    if (tmpInfos.isEmpty()) {                                                                     
2062 -                        // We are missing an application icon, so add this to the workspace                       
2063 -                        added.add(app);                                                                           
2064 -                        // This is a rare event, so lets log it                                                   
2065 -                        Log.e(TAG, "Missing Application on load: " + app);                                        
2066 -                    }                                                                                             
2067 -                }                                                                                                 
2068 -            }                                                                                                     
2069 -            if (!added.isEmpty()) {                                                                               
2070 -                addAndBindAddedWorkspaceApps(context, added);                                                     
2071 -            }                                                                                                     
2072 -        }                                                                                                         
2073 -                                                                                                                  
2074          // check & update map of what's occupied; used to discard overlapping/invalid items                       
2075 -        private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {                 
2076 +        private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {                  
2077              LauncherAppState app = LauncherAppState.getInstance();                                                
2078 -            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
2079 -            final int countX = (int) grid.numColumns;                                                             
2080 -            final int countY = (int) grid.numRows;                                                                
2081 +            InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                     
2082 +            final int countX = (int) profile.numColumns;                                                          
2083 +            final int countY = (int) profile.numRows;                                                             
2084                                                                                                                    
2085              long containerIndex = item.screenId;                                                                  
2086              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
2087                  // Return early if we detect that an item is under the hotseat button                             
2088                  if (mCallbacks == null ||                                                                         
2089                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
2090                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
2091                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
2092                              + item.cellY + ") occupied by all apps");                                             
2093                      return false;                                                                                 
2094                  }                                                                                                 
2095                                                                                                                    
2096                  final ItemInfo[][] hotseatItems =                                                                 
2097                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
2098                                                                                                                    
2099 -                if (item.screenId >= grid.numHotseatIcons) {                                                      
2100 +                if (item.screenId >= profile.numHotseatIcons) {                                                   
2101                      Log.e(TAG, "Error loading shortcut " + item                                                   
2102                              + " into hotseat position " + item.screenId                                           
2103 -                            + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     
2104 +                            + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1)                  
2105                              + ")");                                                                               
2106                      return false;                                                                                 
2107                  }                                                                                                 
2108                                                                                                                    
2109                  if (hotseatItems != null) {                                                                       
2110                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
2111                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
2112                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
2113                                  + item.cellY + ") occupied by "                                                   
2114                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
2115                                  [(int) item.screenId][0]);                                                        
2116                              return false;                                                                         
2117                      } else {                                                                                      
2118                          hotseatItems[(int) item.screenId][0] = item;                                              
2119                          return true;                                                                              
2120                      }                                                                                             
2121                  } else {                                                                                          
2122 -                    final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       
2123 +                    final ItemInfo[][] items = new ItemInfo[(int) profile.numHotseatIcons][1];                    
2124                      items[(int) item.screenId][0] = item;                                                         
2125                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
2126                      return true;                                                                                  
2127                  }                                                                                                 
2128              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
2129                  // Skip further checking if it is not the hotseat or workspace container                          
2130                  return true;                                                                                      
2131              }                                                                                                     
2132                                                                                                                    
2133              if (!occupied.containsKey(item.screenId)) {                                                           
2134                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
2135                  occupied.put(item.screenId, items);                                                               
2136              }                                                                                                     
2137                                                                                                                    
2138              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
2139              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
2140                      item.cellX < 0 || item.cellY < 0 ||                                                           
2141                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
2142                  Log.e(TAG, "Error loading shortcut " + item                                                       
2143                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
2144                          + item.cellX + "," + item.cellY                                                           
2145                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
2146                  return false;                                                                                     
2147              }                                                                                                     
2148                                                                                                                    
2149              // Check if any workspace icons overlap with each other                                               
2150              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
2151                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
2152                      if (screens[x][y] != null) {                                                                  
2153                          Log.e(TAG, "Error loading shortcut " + item                                               
2154                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
2155                              + x + "," + y                                                                         
2156                              + ") occupied by "                                                                    
2157                              + screens[x][y]);                                                                     
2158                          return false;                                                                             
2159                      }                                                                                             
2160                  }                                                                                                 
2161              }                                                                                                     
2162              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
2163                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
2164                      screens[x][y] = item;                                                                         
2165                  }                                                                                                 
2166              }                                                                                                     
2167                                                                                                                    
2168              return true;                                                                                          
2169          }                                                                                                         
2170                                                                                                                    
2171          /** Clears all the sBg data structures */                                                                 
2172          private void clearSBgDataStructures() {                                                                   
2173              synchronized (sBgLock) {                                                                              
2174                  sBgWorkspaceItems.clear();                                                                        
2175                  sBgAppWidgets.clear();                                                                            
2176                  sBgFolders.clear();                                                                               
2177                  sBgItemsIdMap.clear();                                                                            
2178 -                sBgDbIconCache.clear();                                                                           
2179                  sBgWorkspaceScreens.clear();                                                                      
2180              }                                                                                                     
2181          }                                                                                                         
2182                                                                                                                    
2183 -        /** Returns whether this is an upgrade path */                                                            
2184 -        private boolean loadWorkspace() {                                                                         
2185 -            // Log to disk                                                                                        
2186 -            Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
2187 -                                                                                                                  
2188 +        private void loadWorkspace() {                                                                            
2189              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
2190                                                                                                                    
2191              final Context context = mContext;                                                                     
2192              final ContentResolver contentResolver = context.getContentResolver();                                 
2193              final PackageManager manager = context.getPackageManager();                                           
2194              final boolean isSafeMode = manager.isSafeMode();                                                      
2195              final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                      
2196              final boolean isSdCardReady = context.registerReceiver(null,                                          
2197                      new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                                      
2198                                                                                                                    
2199              LauncherAppState app = LauncherAppState.getInstance();                                                
2200 -            DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
2201 -            int countX = (int) grid.numColumns;                                                                   
2202 -            int countY = (int) grid.numRows;                                                                      
2203 +            InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                                     
2204 +            int countX = (int) profile.numColumns;                                                                
2205 +            int countY = (int) profile.numRows;                                                                   
2206                                                                                                                    
2207              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
2208                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
2209                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
2210              }                                                                                                     
2211                                                                                                                    
2212              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
2213                  // append the user's Launcher2 shortcuts                                                          
2214                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
2215                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
2216              } else {                                                                                              
2217                  // Make sure the default workspace is loaded                                                      
2218                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
2219                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                         
2220              }                                                                                                     
2221                                                                                                                    
2222 -            // This code path is for our old migration code and should no longer be exercised                     
2223 -            boolean loadedOldDb = false;                                                                          
2224 -                                                                                                                  
2225 -            // Log to disk                                                                                        
2226 -            Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                           
2227 -                                                                                                                  
2228              synchronized (sBgLock) {                                                                              
2229                  clearSBgDataStructures();                                                                         
2230 -                final HashSet<String> installingPkgs = PackageInstallerCompat                                     
2231 +                final HashMap<String, Integer> installingPkgs = PackageInstallerCompat                            
2232                          .getInstance(mContext).updateAndGetActiveSessionCache();                                  
2233                                                                                                                    
2234                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
2235                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
2236 -                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;                    
2237 +                final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                                    
2238                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
2239                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
2240                                                                                                                    
2241                  // +1 for the hotseat (it can be larger than the workspace)                                       
2242                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
2243                  // before any earlier duplicates)                                                                 
2244 -                final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   
2245 +                final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();                                 
2246                                                                                                                    
2247                  try {                                                                                             
2248                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
2249                      final int intentIndex = c.getColumnIndexOrThrow                                               
2250                              (LauncherSettings.Favorites.INTENT);                                                  
2251                      final int titleIndex = c.getColumnIndexOrThrow                                                
2252                              (LauncherSettings.Favorites.TITLE);                                                   
2253 -                    final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
2254 -                            LauncherSettings.Favorites.ICON_TYPE);                                                
2255 -                    final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
2256 -                    final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
2257 -                            LauncherSettings.Favorites.ICON_PACKAGE);                                             
2258 -                    final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
2259 -                            LauncherSettings.Favorites.ICON_RESOURCE);                                            
2260                      final int containerIndex = c.getColumnIndexOrThrow(                                           
2261                              LauncherSettings.Favorites.CONTAINER);                                                
2262                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
2263                              LauncherSettings.Favorites.ITEM_TYPE);                                                
2264                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
2265                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
2266                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
2267                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
2268                      final int screenIndex = c.getColumnIndexOrThrow(                                              
2269                              LauncherSettings.Favorites.SCREEN);                                                   
2270                      final int cellXIndex = c.getColumnIndexOrThrow                                                
2271                              (LauncherSettings.Favorites.CELLX);                                                   
2272                      final int cellYIndex = c.getColumnIndexOrThrow                                                
2273                              (LauncherSettings.Favorites.CELLY);                                                   
2274                      final int spanXIndex = c.getColumnIndexOrThrow                                                
2275                              (LauncherSettings.Favorites.SPANX);                                                   
2276                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
2277                              LauncherSettings.Favorites.SPANY);                                                    
2278                      final int rankIndex = c.getColumnIndexOrThrow(                                                
2279                              LauncherSettings.Favorites.RANK);                                                     
2280                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
2281                              LauncherSettings.Favorites.RESTORED);                                                 
2282                      final int profileIdIndex = c.getColumnIndexOrThrow(                                           
2283                              LauncherSettings.Favorites.PROFILE_ID);                                               
2284 -                    //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
2285 -                    //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
2286 -                    //        LauncherSettings.Favorites.DISPLAY_MODE);                                           
2287 +                    final int optionsIndex = c.getColumnIndexOrThrow(                                             
2288 +                            LauncherSettings.Favorites.OPTIONS);                                                  
2289 +                    final CursorIconInfo cursorIconInfo = new CursorIconInfo(c);                                  
2290 +                                                                                                                  
2291 +                    final LongSparseArray<UserHandleCompat> allUsers = new LongSparseArray<>();                   
2292 +                    for (UserHandleCompat user : mUserManager.getUserProfiles()) {                                
2293 +                        allUsers.put(mUserManager.getSerialNumberForUser(user), user);                            
2294 +                    }                                                                                             
2295                                                                                                                    
2296                      ShortcutInfo info;                                                                            
2297                      String intentDescription;                                                                     
2298                      LauncherAppWidgetInfo appWidgetInfo;                                                          
2299                      int container;                                                                                
2300                      long id;                                                                                      
2301                      long serialNumber;                                                                            
2302                      Intent intent;                                                                                
2303                      UserHandleCompat user;                                                                        
2304                                                                                                                    
2305                      while (!mStopped && c.moveToNext()) {                                                         
2306                          try {                                                                                     
2307                              int itemType = c.getInt(itemTypeIndex);                                               
2308                              boolean restored = 0 != c.getInt(restoredIndex);                                      
2309                              boolean allowMissingTarget = false;                                                   
2310 +                            container = c.getInt(containerIndex);                                                 
2311                                                                                                                    
2312                              switch (itemType) {                                                                   
2313                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
2314                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
2315                                  id = c.getLong(idIndex);                                                          
2316                                  intentDescription = c.getString(intentIndex);                                     
2317                                  serialNumber = c.getInt(profileIdIndex);                                          
2318 -                                user = mUserManager.getUserForSerialNumber(serialNumber);                         
2319 +                                user = allUsers.get(serialNumber);                                                
2320                                  int promiseType = c.getInt(restoredIndex);                                        
2321                                  int disabledState = 0;                                                            
2322 +                                boolean itemReplaced = false;                                                     
2323                                  if (user == null) {                                                               
2324                                      // User has been deleted remove the item.                                     
2325                                      itemsToRemove.add(id);                                                        
2326                                      continue;                                                                     
2327                                  }                                                                                 
2328                                  try {                                                                             
2329                                      intent = Intent.parseUri(intentDescription, 0);                               
2330                                      ComponentName cn = intent.getComponent();                                     
2331                                      if (cn != null && cn.getPackageName() != null) {                              
2332                                          boolean validPkg = launcherApps.isPackageEnabledForProfile(               
2333                                                  cn.getPackageName(), user);                                       
2334                                          boolean validComponent = validPkg &&                                      
2335                                                  launcherApps.isActivityEnabledForProfile(cn, user);               
2336                                                                                                                    
2337                                          if (validComponent) {                                                     
2338                                              if (restored) {                                                       
2339                                                  // no special handling necessary for this item                    
2340                                                  restoredRows.add(id);                                             
2341                                                  restored = false;                                                 
2342                                              }                                                                     
2343                                          } else if (validPkg) {                                                    
2344                                              intent = null;                                                        
2345                                              if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {         
2346                                                  // We allow auto install apps to have their intent                
2347                                                  // updated after an install.                                      
2348                                                  intent = manager.getLaunchIntentForPackage(                       
2349                                                          cn.getPackageName());                                     
2350                                                  if (intent != null) {                                             
2351                                                      ContentValues values = new ContentValues();                   
2352                                                      values.put(LauncherSettings.Favorites.INTENT,                 
2353                                                              intent.toUri(0));                                     
2354 -                                                    String where = BaseColumns._ID + "= ?";                       
2355 -                                                    String[] args = {Long.toString(id)};                          
2356 -                                                    contentResolver.update(contentUri, values, where, args);      
2357 +                                                    updateItem(id, values);                                       
2358                                                  }                                                                 
2359                                              }                                                                     
2360                                                                                                                    
2361                                              if (intent == null) {                                                 
2362                                                  // The app is installed but the component is no                   
2363                                                  // longer available.                                              
2364                                                  Launcher.addDumpLog(TAG,                                          
2365                                                          "Invalid component removed: " + cn, true);                
2366                                                  itemsToRemove.add(id);                                            
2367                                                  continue;                                                         
2368                                              } else {                                                              
2369                                                  // no special handling necessary for this item                    
2370                                                  restoredRows.add(id);                                             
2371                                                  restored = false;                                                 
2372                                              }                                                                     
2373                                          } else if (restored) {                                                    
2374                                              // Package is not yet available but might be                          
2375                                              // installed later.                                                   
2376                                              Launcher.addDumpLog(TAG,                                              
2377                                                      "package not yet restored: " + cn, true);                     
2378                                                                                                                    
2379                                              if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {         
2380                                                  // Restore has started once.                                      
2381 -                                            } else if (installingPkgs.contains(cn.getPackageName())) {            
2382 +                                            } else if (installingPkgs.containsKey(cn.getPackageName())) {         
2383                                                  // App restore has started. Update the flag                       
2384                                                  promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;                 
2385                                                  ContentValues values = new ContentValues();                       
2386                                                  values.put(LauncherSettings.Favorites.RESTORED,                   
2387                                                          promiseType);                                             
2388 -                                                String where = BaseColumns._ID + "= ?";                           
2389 -                                                String[] args = {Long.toString(id)};                              
2390 -                                                contentResolver.update(contentUri, values, where, args);          
2391 -                                                                                                                  
2392 +                                                updateItem(id, values);                                           
2393 +                                            } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
2394 +                                                // This is a common app. Try to replace this.                     
2395 +                                                int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseTy🔵
2396 +                                                CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, 🔵
2397 +                                                if (parser.findDefaultApp()) {                                    
2398 +                                                    // Default app found. Replace it.                             
2399 +                                                    intent = parser.parsedIntent;                                 
2400 +                                                    cn = intent.getComponent();                                   
2401 +                                                    ContentValues values = parser.parsedValues;                   
2402 +                                                    values.put(LauncherSettings.Favorites.RESTORED, 0);           
2403 +                                                    updateItem(id, values);                                       
2404 +                                                    restored = false;                                             
2405 +                                                    itemReplaced = true;                                          
2406 +                                                                                                                  
2407 +                                                } else if (REMOVE_UNRESTORED_ICONS) {                             
2408 +                                                    Launcher.addDumpLog(TAG,                                      
2409 +                                                            "Unrestored package removed: " + cn, true);           
2410 +                                                    itemsToRemove.add(id);                                        
2411 +                                                    continue;                                                     
2412 +                                                }                                                                 
2413                                              } else if (REMOVE_UNRESTORED_ICONS) {                                 
2414                                                  Launcher.addDumpLog(TAG,                                          
2415                                                          "Unrestored package removed: " + cn, true);               
2416                                                  itemsToRemove.add(id);                                            
2417                                                  continue;                                                         
2418                                              }                                                                     
2419                                          } else if (launcherApps.isAppEnabled(                                     
2420                                                  manager, cn.getPackageName(),                                     
2421                                                  PackageManager.GET_UNINSTALLED_PACKAGES)) {                       
2422                                              // Package is present but not available.                              
2423                                              allowMissingTarget = true;                                            
2424                                              disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;             
2425                                          } else if (!isSdCardReady) {                                              
2426                                              // SdCard is not ready yet. Package might get available,              
2427                                              // once it is ready.                                                  
2428                                              Launcher.addDumpLog(TAG, "Invalid package: " + cn                     
2429                                                      + " (check again later)", true);                              
2430                                              HashSet<String> pkgs = sPendingPackages.get(user);                    
2431                                              if (pkgs == null) {                                                   
2432                                                  pkgs = new HashSet<String>();                                     
2433                                                  sPendingPackages.put(user, pkgs);                                 
2434                                              }                                                                     
2435                                              pkgs.add(cn.getPackageName());                                        
2436                                              allowMissingTarget = true;                                            
2437                                              // Add the icon on the workspace anyway.                              
2438                                                                                                                    
2439                                          } else {                                                                  
2440                                              // Do not wait for external media load anymore.                       
2441                                              // Log the invalid package, and remove it                             
2442                                              Launcher.addDumpLog(TAG,                                              
2443                                                      "Invalid package removed: " + cn, true);                      
2444                                              itemsToRemove.add(id);                                                
2445                                              continue;                                                             
2446                                          }                                                                         
2447                                      } else if (cn == null) {                                                      
2448                                          // For shortcuts with no component, keep them as they are                 
2449                                          restoredRows.add(id);                                                     
2450                                          restored = false;                                                         
2451                                      }                                                                             
2452                                  } catch (URISyntaxException e) {                                                  
2453                                      Launcher.addDumpLog(TAG,                                                      
2454                                              "Invalid uri: " + intentDescription, true);                           
2455                                      continue;                                                                     
2456                                  }                                                                                 
2457                                                                                                                    
2458 -                                if (restored) {                                                                   
2459 +                                boolean useLowResIcon = container >= 0 &&                                         
2460 +                                        c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;                   
2461 +                                                                                                                  
2462 +                                if (itemReplaced) {                                                               
2463 +                                    if (user.equals(UserHandleCompat.myUserHandle())) {                           
2464 +                                        info = getAppShortcutInfo(manager, intent, user, context, null,           
2465 +                                                cursorIconInfo.iconIndex, titleIndex,                             
2466 +                                                false, useLowResIcon);                                            
2467 +                                    } else {                                                                      
2468 +                                        // Don't replace items for other profiles.                                
2469 +                                        itemsToRemove.add(id);                                                    
2470 +                                        continue;                                                                 
2471 +                                    }                                                                             
2472 +                                } else if (restored) {                                                            
2473                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2474                                          Launcher.addDumpLog(TAG,                                                  
2475                                                  "constructing info for partially restored package",               
2476                                                  true);                                                            
2477 -                                        info = getRestoredItemInfo(c, titleIndex, intent, promiseType);           
2478 +                                        info = getRestoredItemInfo(c, titleIndex, intent,                         
2479 +                                                promiseType, itemType, cursorIconInfo, context);                  
2480                                          intent = getRestoredItemIntent(c, context, intent);                       
2481                                      } else {                                                                      
2482                                          // Don't restore items for other profiles.                                
2483                                          itemsToRemove.add(id);                                                    
2484                                          continue;                                                                 
2485                                      }                                                                             
2486                                  } else if (itemType ==                                                            
2487                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
2488 -                                    info = getShortcutInfo(manager, intent, user, context, c,                     
2489 -                                            iconIndex, titleIndex, mLabelCache, allowMissingTarget);              
2490 +                                    info = getAppShortcutInfo(manager, intent, user, context, c,                  
2491 +                                            cursorIconInfo.iconIndex, titleIndex,                                 
2492 +                                            allowMissingTarget, useLowResIcon);                                   
2493                                  } else {                                                                          
2494 -                                    info = getShortcutInfo(c, context, iconTypeIndex,                             
2495 -                                            iconPackageIndex, iconResourceIndex, iconIndex,                       
2496 -                                            titleIndex);                                                          
2497 +                                    info = getShortcutInfo(c, context, titleIndex, cursorIconInfo);               
2498                                                                                                                    
2499                                      // App shortcuts that used to be automatically added to Launcher              
2500                                      // didn't always have the correct intent flags set, so do that                
2501                                      // here                                                                       
2502                                      if (intent.getAction() != null &&                                             
2503                                          intent.getCategories() != null &&                                         
2504                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
2505                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
2506                                          intent.addFlags(                                                          
2507                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
2508                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
2509                                      }                                                                             
2510                                  }                                                                                 
2511                                                                                                                    
2512                                  if (info != null) {                                                               
2513                                      info.id = id;                                                                 
2514                                      info.intent = intent;                                                         
2515 -                                    container = c.getInt(containerIndex);                                         
2516                                      info.container = container;                                                   
2517                                      info.screenId = c.getInt(screenIndex);                                        
2518                                      info.cellX = c.getInt(cellXIndex);                                            
2519                                      info.cellY = c.getInt(cellYIndex);                                            
2520                                      info.rank = c.getInt(rankIndex);                                              
2521                                      info.spanX = 1;                                                               
2522                                      info.spanY = 1;                                                               
2523                                      info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);                   
2524 +                                    if (info.promisedIntent != null) {                                            
2525 +                                        info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);       
2526 +                                    }                                                                             
2527                                      info.isDisabled = disabledState;                                              
2528                                      if (isSafeMode && !Utilities.isSystemApp(context, intent)) {                  
2529                                          info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;                   
2530                                      }                                                                             
2531                                                                                                                    
2532                                      // check & update map of what's occupied                                      
2533                                      if (!checkItemPlacement(occupied, info)) {                                    
2534                                          itemsToRemove.add(id);                                                    
2535                                          break;                                                                    
2536 +                                    }                                                                             
2537 +                                                                                                                  
2538 +                                    if (restored) {                                                               
2539 +                                        ComponentName cn = info.getTargetComponent();                             
2540 +                                        if (cn != null) {                                                         
2541 +                                            Integer progress = installingPkgs.get(cn.getPackageName());           
2542 +                                            if (progress != null) {                                               
2543 +                                                info.setInstallProgress(progress);                                
2544 +                                            } else {                                                              
2545 +                                                info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;         
2546 +                                            }                                                                     
2547 +                                        }                                                                         
2548                                      }                                                                             
2549                                                                                                                    
2550                                      switch (container) {                                                          
2551                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2552                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2553                                          sBgWorkspaceItems.add(info);                                              
2554                                          break;                                                                    
2555                                      default:                                                                      
2556                                          // Item is in a user folder                                               
2557                                          FolderInfo folderInfo =                                                   
2558                                                  findOrMakeFolder(sBgFolders, container);                          
2559                                          folderInfo.add(info);                                                     
2560                                          break;                                                                    
2561                                      }                                                                             
2562                                      sBgItemsIdMap.put(info.id, info);                                             
2563 -                                                                                                                  
2564 -                                    // now that we've loaded everthing re-save it with the                        
2565 -                                    // icon in case it disappears somehow.                                        
2566 -                                    queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
2567                                  } else {                                                                          
2568                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
2569                                  }                                                                                 
2570                                  break;                                                                            
2571                                                                                                                    
2572                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
2573                                  id = c.getLong(idIndex);                                                          
2574                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
2575                                                                                                                    
2576 +                                // Do not trim the folder label, as is was set by the user.                       
2577                                  folderInfo.title = c.getString(titleIndex);                                       
2578                                  folderInfo.id = id;                                                               
2579 -                                container = c.getInt(containerIndex);                                             
2580                                  folderInfo.container = container;                                                 
2581                                  folderInfo.screenId = c.getInt(screenIndex);                                      
2582                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
2583                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
2584                                  folderInfo.spanX = 1;                                                             
2585                                  folderInfo.spanY = 1;                                                             
2586 +                                folderInfo.options = c.getInt(optionsIndex);                                      
2587                                                                                                                    
2588                                  // check & update map of what's occupied                                          
2589                                  if (!checkItemPlacement(occupied, folderInfo)) {                                  
2590                                      itemsToRemove.add(id);                                                        
2591                                      break;                                                                        
2592                                  }                                                                                 
2593                                                                                                                    
2594                                  switch (container) {                                                              
2595                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2596                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2597                                          sBgWorkspaceItems.add(folderInfo);                                        
2598                                          break;                                                                    
2599                                  }                                                                                 
2600                                                                                                                    
2601                                  if (restored) {                                                                   
2602                                      // no special handling required for restored folders                          
2603                                      restoredRows.add(id);                                                         
2604                                  }                                                                                 
2605                                                                                                                    
2606                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
2607                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
2608                                  break;                                                                            
2609                                                                                                                    
2610                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
2611                              case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                           
2612                                  // Read all Launcher-specific widget details                                      
2613                                  boolean customWidget = itemType ==                                                
2614                                      LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;                        
2615                                                                                                                    
2616                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
2617 -                                serialNumber= c.getLong(profileIdIndex);                                          
2618 +                                serialNumber = c.getLong(profileIdIndex);                                         





2619                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
2620                                  id = c.getLong(idIndex);                                                          
2621 +                                user = allUsers.get(serialNumber);                                                
2622 +                                if (user == null) {                                                               
2623 +                                    itemsToRemove.add(id);                                                        
2624 +                                    continue;                                                                     
2625 +                                }                                                                                 
2626 +                                                                                                                  
2627                                  final ComponentName component =                                                   
2628                                          ComponentName.unflattenFromString(savedProvider);                         
2629                                                                                                                    
2630                                  final int restoreStatus = c.getInt(restoredIndex);                                
2631                                  final boolean isIdValid = (restoreStatus &                                        
2632                                          LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                            
2633 -                                                                                                                  
2634                                  final boolean wasProviderReady = (restoreStatus &                                 
2635                                          LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;                      
2636                                                                                                                    
2637                                  final LauncherAppWidgetProviderInfo provider =                                    
2638                                          LauncherModel.getProviderInfo(context,                                    
2639                                                  ComponentName.unflattenFromString(savedProvider),                 
2640 -                                                mUserManager.getUserForSerialNumber(serialNumber));               
2641 +                                                user);                                                            
2642                                                                                                                    
2643                                  final boolean isProviderReady = isValidProvider(provider);                        
2644                                  if (!isSafeMode && !customWidget &&                                               
2645                                          wasProviderReady && !isProviderReady) {                                   
2646                                      String log = "Deleting widget that isn't installed anymore: "                 
2647                                              + "id=" + id + " appWidgetId=" + appWidgetId;                         
2648                                                                                                                    
2649                                      Log.e(TAG, log);                                                              
2650                                      Launcher.addDumpLog(TAG, log, false);                                         
2651                                      itemsToRemove.add(id);                                                        
2652                                  } else {                                                                          
2653                                      if (isProviderReady) {                                                        
2654                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2655                                                  provider.provider);                                               
2656 -                                                                                                                  
2657 -                                        if (!customWidget) {                                                      
2658 -                                            int[] minSpan =                                                       
2659 -                                                    Launcher.getMinSpanForWidget(context, provider);              
2660 -                                            appWidgetInfo.minSpanX = minSpan[0];                                  
2661 -                                            appWidgetInfo.minSpanY = minSpan[1];                                  
2662 -                                        }                                                                         
2663                                                                                                                    
2664                                          int status = restoreStatus;                                               
2665                                          if (!wasProviderReady) {                                                  
2666                                              // If provider was not previously ready, update the                   
2667                                              // status and UI flag.                                                
2668                                                                                                                    
2669                                              // Id would be valid only if the widget restore broadcast was received🔵
2670                                              if (isIdValid) {                                                      
2671                                                  status = LauncherAppWidgetInfo.RESTORE_COMPLETED;                 
2672                                              } else {                                                              
2673                                                  status &= ~LauncherAppWidgetInfo                                  
2674                                                          .FLAG_PROVIDER_NOT_READY;                                 
2675                                              }                                                                     
2676                                          }                                                                         
2677                                          appWidgetInfo.restoreStatus = status;                                     
2678                                      } else {                                                                      
2679                                          Log.v(TAG, "Widget restore pending id=" + id                              
2680                                                  + " appWidgetId=" + appWidgetId                                   
2681                                                  + " status =" + restoreStatus);                                   
2682                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2683                                                  component);                                                       
2684                                          appWidgetInfo.restoreStatus = restoreStatus;                              
2685 +                                        Integer installProgress = installingPkgs.get(component.getPackageName()); 
2686                                                                                                                    
2687                                          if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {  
2688                                              // Restore has started once.                                          
2689 -                                        } else if (installingPkgs.contains(component.getPackageName())) {         
2690 +                                        } else if (installProgress != null) {                                     
2691                                              // App restore has started. Update the flag                           
2692                                              appWidgetInfo.restoreStatus |=                                        
2693                                                      LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;                   
2694                                          } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {                      
2695                                              Launcher.addDumpLog(TAG,                                              
2696                                                      "Unrestored widget removed: " + component, true);             
2697                                              itemsToRemove.add(id);                                                
2698                                              continue;                                                             
2699                                          }                                                                         
2700 +                                                                                                                  
2701 +                                        appWidgetInfo.installProgress =                                           
2702 +                                                installProgress == null ? 0 : installProgress;                    
2703                                      }                                                                             
2704                                                                                                                    
2705                                      appWidgetInfo.id = id;                                                        
2706                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
2707                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
2708                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
2709                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
2710                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   

2711                                                                                                                    
2712 -                                    if (!customWidget) {                                                          
2713 -                                        int[] minSpan = Launcher.getMinSpanForWidget(context, provider);          
2714 -                                        appWidgetInfo.minSpanX = minSpan[0];                                      
2715 -                                        appWidgetInfo.minSpanY = minSpan[1];                                      
2716 -                                    }                                                                             
2717 -                                                                                                                  
2718 -                                    container = c.getInt(containerIndex);                                         
2719                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
2720                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
2721                                          Log.e(TAG, "Widget found where container != " +                           
2722                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
2723                                          continue;                                                                 
2724                                      }                                                                             
2725                                                                                                                    
2726 -                                    appWidgetInfo.container = c.getInt(containerIndex);                           
2727 +                                    appWidgetInfo.container = container;                                          
2728                                      // check & update map of what's occupied                                      
2729                                      if (!checkItemPlacement(occupied, appWidgetInfo)) {                           
2730                                          itemsToRemove.add(id);                                                    
2731                                          break;                                                                    
2732                                      }                                                                             
2733                                                                                                                    
2734                                      if (!customWidget) {                                                          
2735                                          String providerName =                                                     
2736                                                  appWidgetInfo.providerName.flattenToString();                     
2737                                          if (!providerName.equals(savedProvider) ||                                
2738                                                  (appWidgetInfo.restoreStatus != restoreStatus)) {                 
2739                                              ContentValues values = new ContentValues();                           
2740                                              values.put(                                                           
2741                                                      LauncherSettings.Favorites.APPWIDGET_PROVIDER,                
2742                                                      providerName);                                                
2743                                              values.put(LauncherSettings.Favorites.RESTORED,                       
2744                                                      appWidgetInfo.restoreStatus);                                 
2745 -                                            String where = BaseColumns._ID + "= ?";                               
2746 -                                            String[] args = {Long.toString(id)};                                  
2747 -                                            contentResolver.update(contentUri, values, where, args);              
2748 +                                            updateItem(id, values);                                               
2749                                          }                                                                         
2750                                      }                                                                             
2751                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2752                                      sBgAppWidgets.add(appWidgetInfo);                                             
2753                                  }                                                                                 
2754                                  break;                                                                            
2755                              }                                                                                     
2756                          } catch (Exception e) {                                                                   
2757                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2758                          }                                                                                         
2759                      }                                                                                             
2760                  } finally {                                                                                       
2761                      if (c != null) {                                                                              
2762                          c.close();                                                                                
2763                      }                                                                                             
2764                  }                                                                                                 
2765                                                                                                                    
2766                  // Break early if we've stopped loading                                                           
2767                  if (mStopped) {                                                                                   
2768                      clearSBgDataStructures();                                                                     
2769 -                    return false;                                                                                 
2770 +                    return;                                                                                       
2771                  }                                                                                                 
2772                                                                                                                    
2773                  if (itemsToRemove.size() > 0) {                                                                   
2774 -                    ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2775 -                            contentUri);                                                                          
2776                      // Remove dead items                                                                          
2777 -                    for (long id : itemsToRemove) {                                                               
2778 -                        if (DEBUG_LOADERS) {                                                                      
2779 -                            Log.d(TAG, "Removed id = " + id);                                                     
2780 -                        }                                                                                         
2781 -                        // Don't notify content observers                                                         
2782 -                        try {                                                                                     
2783 -                            client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2784 -                                    null, null);                                                                  
2785 -                        } catch (RemoteException e) {                                                             
2786 -                            Log.w(TAG, "Could not remove id = " + id);                                            
2787 -                        }                                                                                         
2788 +                    contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI,                                
2789 +                            Utilities.createDbSelectionQuery(                                                     
2790 +                                    LauncherSettings.Favorites._ID, itemsToRemove), null);                        
2791 +                    if (DEBUG_LOADERS) {                                                                          
2792 +                        Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(                               
2793 +                                LauncherSettings.Favorites._ID, itemsToRemove));                                  
2794 +                    }                                                                                             
2795 +                                                                                                                  
2796 +                    // Remove any empty folder                                                                    
2797 +                    for (long folderId : LauncherAppState.getLauncherProvider()                                   
2798 +                            .deleteEmptyFolders()) {                                                              
2799 +                        sBgWorkspaceItems.remove(sBgFolders.get(folderId));                                       
2800 +                        sBgFolders.remove(folderId);                                                              
2801 +                        sBgItemsIdMap.remove(folderId);                                                           
2802                      }                                                                                             
2803                  }                                                                                                 
2804                                                                                                                    
2805                  if (restoredRows.size() > 0) {                                                                    
2806 -                    ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2807 -                            contentUri);                                                                          
2808                      // Update restored items that no longer require special handling                              
2809 -                    try {                                                                                         
2810 -                        StringBuilder selectionBuilder = new StringBuilder();                                     
2811 -                        selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2812 -                        selectionBuilder.append(" IN (");                                                         
2813 -                        selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2814 -                        selectionBuilder.append(")");                                                             
2815 -                        ContentValues values = new ContentValues();                                               
2816 -                        values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2817 -                        updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                    
2818 -                                values, selectionBuilder.toString(), null);                                       
2819 -                    } catch (RemoteException e) {                                                                 
2820 -                        Log.w(TAG, "Could not update restored rows");                                             
2821 -                    }                                                                                             
2822 +                    ContentValues values = new ContentValues();                                                   
2823 +                    values.put(LauncherSettings.Favorites.RESTORED, 0);                                           
2824 +                    contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values,                        
2825 +                            Utilities.createDbSelectionQuery(                                                     
2826 +                                    LauncherSettings.Favorites._ID, restoredRows), null);                         
2827                  }                                                                                                 
2828                                                                                                                    
2829                  if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                              
2830                      context.registerReceiver(new AppsAvailabilityCheck(),                                         
2831                              new IntentFilter(StartupReceiver.SYSTEM_READY),                                       
2832                              null, sWorker);                                                                       
2833                  }                                                                                                 
2834                                                                                                                    
2835 -                if (loadedOldDb) {                                                                                
2836 -                    long maxScreenId = 0;                                                                         
2837 -                    // If we're importing we use the old screen order.                                            
2838 -                    for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2839 -                        long screenId = item.screenId;                                                            
2840 -                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2841 -                                !sBgWorkspaceScreens.contains(screenId)) {                                        
2842 -                            sBgWorkspaceScreens.add(screenId);                                                    
2843 -                            if (screenId > maxScreenId) {                                                         
2844 -                                maxScreenId = screenId;                                                           
2845 -                            }                                                                                     
2846 -                        }                                                                                         
2847 -                    }                                                                                             
2848 -                    Collections.sort(sBgWorkspaceScreens);                                                        
2849 -                    // Log to disk                                                                                
2850 -                    Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);                   
2851 -                    Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2852 -                            TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2853 -                                                                                                                  
2854 -                    LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);                        
2855 +                sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                                     
2856 +                                                                                                                  
2857 +                // Remove any empty screens                                                                       
2858 +                ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                         
2859 +                for (ItemInfo item: sBgItemsIdMap) {                                                              
2860 +                    long screenId = item.screenId;                                                                
2861 +                    if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                         
2862 +                            unusedScreens.contains(screenId)) {                                                   
2863 +                        unusedScreens.remove(screenId);                                                           
2864 +                    }                                                                                             
2865 +                }                                                                                                 
2866 +                                                                                                                  
2867 +                // If there are any empty screens remove them, and update.                                        
2868 +                if (unusedScreens.size() != 0) {                                                                  
2869 +                    sBgWorkspaceScreens.removeAll(unusedScreens);                                                 
2870                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2871 -                                                                                                                  
2872 -                    // Update the max item id after we load an old db                                             
2873 -                    long maxItemId = 0;                                                                           
2874 -                    // If we're importing we use the old screen order.                                            
2875 -                    for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2876 -                        maxItemId = Math.max(maxItemId, item.id);                                                 
2877 -                    }                                                                                             
2878 -                    LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                            
2879 -                } else {                                                                                          
2880 -                    TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);                     
2881 -                    for (Integer i : orderedScreens.keySet()) {                                                   
2882 -                        sBgWorkspaceScreens.add(orderedScreens.get(i));                                           
2883 -                    }                                                                                             
2884 -                    // Log to disk                                                                                
2885 -                    Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2886 -                            TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2887 -                                                                                                                  
2888 -                    // Remove any empty screens                                                                   
2889 -                    ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                     
2890 -                    for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2891 -                        long screenId = item.screenId;                                                            
2892 -                        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2893 -                                unusedScreens.contains(screenId)) {                                               
2894 -                            unusedScreens.remove(screenId);                                                       
2895 -                        }                                                                                         
2896 -                    }                                                                                             
2897 -                                                                                                                  
2898 -                    // If there are any empty screens remove them, and update.                                    
2899 -                    if (unusedScreens.size() != 0) {                                                              
2900 -                        // Log to disk                                                                            
2901 -                        Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                 
2902 -                                TextUtils.join(", ", unusedScreens), true);                                       
2903 -                                                                                                                  
2904 -                        sBgWorkspaceScreens.removeAll(unusedScreens);                                             
2905 -                        updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                 
2906 -                    }                                                                                             
2907                  }                                                                                                 
2908                                                                                                                    
2909                  if (DEBUG_LOADERS) {                                                                              
2910                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2911                      Log.d(TAG, "workspace layout: ");                                                             
2912                      int nScreens = occupied.size();                                                               
2913                      for (int y = 0; y < countY; y++) {                                                            
2914                          String line = "";                                                                         
2915                                                                                                                    
2916 -                        Iterator<Long> iter = occupied.keySet().iterator();                                       
2917 -                        while (iter.hasNext()) {                                                                  
2918 -                            long screenId = iter.next();                                                          
2919 +                        for (int i = 0; i < nScreens; i++) {                                                      
2920 +                            long screenId = occupied.keyAt(i);                                                    
2921                              if (screenId > 0) {                                                                   
2922                                  line += " | ";                                                                    
2923                              }                                                                                     
2924 +                            ItemInfo[][] screen = occupied.valueAt(i);                                            
2925                              for (int x = 0; x < countX; x++) {                                                    
2926 -                                ItemInfo[][] screen = occupied.get(screenId);                                     
2927                                  if (x < screen.length && y < screen[x].length) {                                  
2928                                      line += (screen[x][y] != null) ? "#" : ".";                                   
2929                                  } else {                                                                          
2930                                      line += "!";                                                                  
2931                                  }                                                                                 
2932                              }                                                                                     
2933                          }                                                                                         
2934                          Log.d(TAG, "[ " + line + " ]");                                                           
2935                      }                                                                                             
2936                  }                                                                                                 
2937              }                                                                                                     
2938 -            return loadedOldDb;                                                                                   
2939 +        }                                                                                                         
2940 +                                                                                                                  
2941 +        /**                                                                                                       
2942 +         * Partially updates the item without any notification. Must be called on the worker thread.              
2943 +         */                                                                                                       
2944 +        private void updateItem(long itemId, ContentValues update) {                                              
2945 +            mContext.getContentResolver().update(                                                                 
2946 +                    LauncherSettings.Favorites.CONTENT_URI,                                                       
2947 +                    update,                                                                                       
2948 +                    BaseColumns._ID + "= ?",                                                                      
2949 +                    new String[]{Long.toString(itemId)});                                                         
2950          }                                                                                                         
2951                                                                                                                    
2952          /** Filters the set of items who are directly or indirectly (via another container) on the                
2953           * specified screen. */                                                                                   
2954          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2955                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2956                  ArrayList<ItemInfo> currentScreenItems,                                                           
2957                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2958              // Purge any null ItemInfos                                                                           
2959              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2960              while (iter.hasNext()) {                                                                              
2961                  ItemInfo i = iter.next();                                                                         
2962                  if (i == null) {                                                                                  
2963                      iter.remove();                                                                                
2964                  }                                                                                                 
2965              }                                                                                                     
2966                                                                                                                    
2967              // Order the set of items by their containers first, this allows use to walk through the              
2968              // list sequentially, build up a list of containers that are in the specified screen,                 
2969              // as well as all items in those containers.                                                          
2970              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2971              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2972                  @Override                                                                                         
2973                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2974                      return (int) (lhs.container - rhs.container);                                                 
2975                  }                                                                                                 
2976              });                                                                                                   
2977              for (ItemInfo info : allWorkspaceItems) {                                                             
2978                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2979                      if (info.screenId == currentScreenId) {                                                       
2980                          currentScreenItems.add(info);                                                             
2981                          itemsOnScreen.add(info.id);                                                               
2982                      } else {                                                                                      
2983                          otherScreenItems.add(info);                                                               
2984                      }                                                                                             
2985                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2986                      currentScreenItems.add(info);                                                                 
2987                      itemsOnScreen.add(info.id);                                                                   
2988                  } else {                                                                                          
2989                      if (itemsOnScreen.contains(info.container)) {                                                 
2990                          currentScreenItems.add(info);                                                             
2991                          itemsOnScreen.add(info.id);                                                               
2992                      } else {                                                                                      
2993                          otherScreenItems.add(info);                                                               
2994                      }                                                                                             
2995                  }                                                                                                 
2996              }                                                                                                     
2997          }                                                                                                         
2998                                                                                                                    
2999          /** Filters the set of widgets which are on the specified screen. */                                      
3000          private void filterCurrentAppWidgets(long currentScreenId,                                                
3001                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
3002                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
3003                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
3004                                                                                                                    
3005              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
3006                  if (widget == null) continue;                                                                     
3007                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
3008                          widget.screenId == currentScreenId) {                                                     
3009                      currentScreenWidgets.add(widget);                                                             
3010                  } else {                                                                                          
3011                      otherScreenWidgets.add(widget);                                                               
3012                  }                                                                                                 
3013              }                                                                                                     
3014          }                                                                                                         
3015                                                                                                                    
3016          /** Filters the set of folders which are on the specified screen. */                                      
3017          private void filterCurrentFolders(long currentScreenId,                                                   
3018 -                HashMap<Long, ItemInfo> itemsIdMap,                                                               
3019 -                HashMap<Long, FolderInfo> folders,                                                                
3020 -                HashMap<Long, FolderInfo> currentScreenFolders,                                                   
3021 -                HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
3022 -                                                                                                                  
3023 -            for (long id : folders.keySet()) {                                                                    
3024 +                LongArrayMap<ItemInfo> itemsIdMap,                                                                
3025 +                LongArrayMap<FolderInfo> folders,                                                                 
3026 +                LongArrayMap<FolderInfo> currentScreenFolders,                                                    
3027 +                LongArrayMap<FolderInfo> otherScreenFolders) {                                                    
3028 +                                                                                                                  
3029 +            int total = folders.size();                                                                           
3030 +            for (int i = 0; i < total; i++) {                                                                     
3031 +                long id = folders.keyAt(i);                                                                       
3032 +                FolderInfo folder = folders.valueAt(i);                                                           
3033 +                                                                                                                  
3034                  ItemInfo info = itemsIdMap.get(id);                                                               
3035 -                FolderInfo folder = folders.get(id);                                                              
3036                  if (info == null || folder == null) continue;                                                     
3037                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
3038                          info.screenId == currentScreenId) {                                                       
3039                      currentScreenFolders.put(id, folder);                                                         
3040                  } else {                                                                                          
3041                      otherScreenFolders.put(id, folder);                                                           
3042                  }                                                                                                 
3043              }                                                                                                     
3044          }                                                                                                         
3045                                                                                                                    
3046          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
3047           * right) */                                                                                              
3048          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
3049              final LauncherAppState app = LauncherAppState.getInstance();                                          
3050 -            final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   
3051 +            final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();                               
3052              // XXX: review this                                                                                   
3053              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
3054                  @Override                                                                                         
3055                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
3056 -                    int cellCountX = (int) grid.numColumns;                                                       
3057 -                    int cellCountY = (int) grid.numRows;                                                          
3058 +                    int cellCountX = (int) profile.numColumns;                                                    
3059 +                    int cellCountY = (int) profile.numRows;                                                       
3060                      int screenOffset = cellCountX * cellCountY;                                                   
3061                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
3062                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
3063                              lhs.cellY * cellCountX + lhs.cellX);                                                  
3064                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
3065                              rhs.cellY * cellCountX + rhs.cellX);                                                  
3066                      return (int) (lr - rr);                                                                       
3067                  }                                                                                                 
3068              });                                                                                                   
3069          }                                                                                                         
3070                                                                                                                    
3071          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
3072                  final ArrayList<Long> orderedScreens) {                                                           
3073              final Runnable r = new Runnable() {                                                                   
3074                  @Override                                                                                         
3075                  public void run() {                                                                               
3076                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
3077                      if (callbacks != null) {                                                                      
3078                          callbacks.bindScreens(orderedScreens);                                                    
3079                      }                                                                                             
3080                  }                                                                                                 
3081              };                                                                                                    
3082 -            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
3083 +            runOnMainThread(r);                                                                                   
3084          }                                                                                                         
3085                                                                                                                    
3086          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
3087                  final ArrayList<ItemInfo> workspaceItems,                                                         
3088                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
3089 -                final HashMap<Long, FolderInfo> folders,                                                          
3090 +                final LongArrayMap<FolderInfo> folders,                                                           
3091                  ArrayList<Runnable> deferredBindRunnables) {                                                      
3092                                                                                                                    
3093              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
3094                                                                                                                    
3095              // Bind the workspace items                                                                           
3096              int N = workspaceItems.size();                                                                        
3097              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
3098                  final int start = i;                                                                              
3099                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
3100                  final Runnable r = new Runnable() {                                                               
3101                      @Override                                                                                     
3102                      public void run() {                                                                           
3103                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
3104                          if (callbacks != null) {                                                                  
3105                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
3106                                      false);                                                                       
3107                          }                                                                                         
3108                      }                                                                                             
3109                  };                                                                                                
3110                  if (postOnMainThread) {                                                                           
3111                      synchronized (deferredBindRunnables) {                                                        
3112                          deferredBindRunnables.add(r);                                                             
3113                      }                                                                                             
3114                  } else {                                                                                          
3115 -                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
3116 +                    runOnMainThread(r);                                                                           
3117                  }                                                                                                 
3118              }                                                                                                     
3119                                                                                                                    
3120              // Bind the folders                                                                                   
3121              if (!folders.isEmpty()) {                                                                             
3122                  final Runnable r = new Runnable() {                                                               
3123                      public void run() {                                                                           
3124                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
3125                          if (callbacks != null) {                                                                  
3126                              callbacks.bindFolders(folders);                                                       
3127                          }                                                                                         
3128                      }                                                                                             
3129                  };                                                                                                
3130                  if (postOnMainThread) {                                                                           
3131                      synchronized (deferredBindRunnables) {                                                        
3132                          deferredBindRunnables.add(r);                                                             
3133                      }                                                                                             
3134                  } else {                                                                                          
3135 -                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
3136 +                    runOnMainThread(r);                                                                           
3137                  }                                                                                                 
3138              }                                                                                                     
3139                                                                                                                    
3140              // Bind the widgets, one at a time                                                                    
3141              N = appWidgets.size();                                                                                
3142              for (int i = 0; i < N; i++) {                                                                         
3143                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
3144                  final Runnable r = new Runnable() {                                                               
3145                      public void run() {                                                                           
3146                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
3147                          if (callbacks != null) {                                                                  
3148                              callbacks.bindAppWidget(widget);                                                      
3149                          }                                                                                         
3150                      }                                                                                             
3151                  };                                                                                                
3152                  if (postOnMainThread) {                                                                           
3153                      deferredBindRunnables.add(r);                                                                 
3154                  } else {                                                                                          
3155 -                    runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
3156 +                    runOnMainThread(r);                                                                           
3157                  }                                                                                                 
3158              }                                                                                                     
3159          }                                                                                                         
3160                                                                                                                    
3161          /**                                                                                                       
3162           * Binds all loaded data to actual views on the main thread.                                              
3163           */                                                                                                       
3164 -        private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {                        
3165 +        private void bindWorkspace(int synchronizeBindPage) {                                                     
3166              final long t = SystemClock.uptimeMillis();                                                            
3167              Runnable r;                                                                                           
3168                                                                                                                    
3169              // Don't use these two variables in any of the callback runnables.                                    
3170              // Otherwise we hold a reference to them.                                                             
3171              final Callbacks oldCallbacks = mCallbacks.get();                                                      
3172              if (oldCallbacks == null) {                                                                           
3173                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
3174                  Log.w(TAG, "LoaderTask running with no launcher");                                                
3175                  return;                                                                                           
3176              }                                                                                                     
3177                                                                                                                    
3178              // Save a copy of all the bg-thread collections                                                       
3179              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
3180              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
3181                      new ArrayList<LauncherAppWidgetInfo>();                                                       
3182 -            HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
3183 -            HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
3184              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             
3185 +                                                                                                                  
3186 +            final LongArrayMap<FolderInfo> folders;                                                               
3187 +            final LongArrayMap<ItemInfo> itemsIdMap;                                                              
3188 +                                                                                                                  
3189              synchronized (sBgLock) {                                                                              
3190                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
3191                  appWidgets.addAll(sBgAppWidgets);                                                                 
3192 -                folders.putAll(sBgFolders);                                                                       
3193 -                itemsIdMap.putAll(sBgItemsIdMap);                                                                 
3194                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     
3195 +                                                                                                                  
3196 +                folders = sBgFolders.clone();                                                                     
3197 +                itemsIdMap = sBgItemsIdMap.clone();                                                               
3198              }                                                                                                     
3199                                                                                                                    
3200              final boolean isLoadingSynchronously =                                                                
3201                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
3202              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
3203                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
3204              if (currScreen >= orderedScreenIds.size()) {                                                          
3205                  // There may be no workspace screens (just hotseat items and an empty page).                      
3206                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
3207              }                                                                                                     
3208              final int currentScreen = currScreen;                                                                 
3209              final long currentScreenId = currentScreen < 0                                                        
3210                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
3211                                                                                                                    
3212              // Load all the items that are on the current page first (and in the process, unbind                  
3213              // all the existing workspace items before we call startBinding() below.                              
3214              unbindWorkspaceItemsOnMainThread();                                                                   
3215                                                                                                                    
3216              // Separate the items that are on the current screen, and all the other remaining items               
3217              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
3218              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
3219              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
3220                      new ArrayList<LauncherAppWidgetInfo>();                                                       
3221              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
3222                      new ArrayList<LauncherAppWidgetInfo>();                                                       
3223 -            HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
3224 -            HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             
3225 +            LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();                                       
3226 +            LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();                                         
3227                                                                                                                    
3228              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
3229                      otherWorkspaceItems);                                                                         
3230              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
3231                      otherAppWidgets);                                                                             
3232              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
3233                      otherFolders);                                                                                
3234              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
3235              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
3236                                                                                                                    
3237              // Tell the workspace that we're about to start binding items                                         
3238              r = new Runnable() {                                                                                  
3239                  public void run() {                                                                               
3240                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
3241                      if (callbacks != null) {                                                                      
3242                          callbacks.startBinding();                                                                 
3243                      }                                                                                             
3244                  }                                                                                                 
3245              };                                                                                                    
3246 -            runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
3247 +            runOnMainThread(r);                                                                                   
3248                                                                                                                    
3249              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
3250                                                                                                                    
3251              // Load items on the current page                                                                     
3252              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
3253                      currentFolders, null);                                                                        
3254              if (isLoadingSynchronously) {                                                                         
3255                  r = new Runnable() {                                                                              
3256                      public void run() {                                                                           
3257                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
3258                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
3259                              callbacks.onPageBoundSynchronously(currentScreen);                                    
3260                          }                                                                                         
3261                      }                                                                                             
3262                  };                                                                                                
3263 -                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
3264 +                runOnMainThread(r);                                                                               
3265              }                                                                                                     
3266                                                                                                                    
3267              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
3268              // work until after the first render)                                                                 
3269              synchronized (mDeferredBindRunnables) {                                                               
3270                  mDeferredBindRunnables.clear();                                                                   
3271              }                                                                                                     
3272              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
3273                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
3274                                                                                                                    
3275              // Tell the workspace that we're done binding items                                                   
3276              r = new Runnable() {                                                                                  
3277                  public void run() {                                                                               
3278                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
3279                      if (callbacks != null) {                                                                      
3280 -                        callbacks.finishBindingItems(isUpgradePath);                                              
3281 +                        callbacks.finishBindingItems();                                                           
3282                      }                                                                                             
3283                                                                                                                    
3284                      // If we're profiling, ensure this is the last thing in the queue.                            
3285                      if (DEBUG_LOADERS) {                                                                          
3286                          Log.d(TAG, "bound workspace in "                                                          
3287                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
3288                      }                                                                                             
3289                                                                                                                    
3290                      mIsLoadingAndBindingWorkspace = false;                                                        
3291                  }                                                                                                 
3292              };                                                                                                    
3293              if (isLoadingSynchronously) {                                                                         
3294                  synchronized (mDeferredBindRunnables) {                                                           
3295                      mDeferredBindRunnables.add(r);                                                                
3296                  }                                                                                                 
3297              } else {                                                                                              
3298 -                runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
3299 +                runOnMainThread(r);                                                                               
3300              }                                                                                                     
3301          }                                                                                                         
3302                                                                                                                    
3303          private void loadAndBindAllApps() {                                                                       
3304              if (DEBUG_LOADERS) {                                                                                  
3305                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
3306              }                                                                                                     
3307              if (!mAllAppsLoaded) {                                                                                
3308                  loadAllApps();                                                                                    
3309                  synchronized (LoaderTask.this) {                                                                  
3310                      if (mStopped) {                                                                               
3311                          return;                                                                                   
3312                      }                                                                                             
3313 +                }                                                                                                 
3314 +                updateIconCache();                                                                                
3315 +                synchronized (LoaderTask.this) {                                                                  
3316 +                    if (mStopped) {                                                                               
3317 +                        return;                                                                                   
3318 +                    }                                                                                             
3319                      mAllAppsLoaded = true;                                                                        
3320                  }                                                                                                 
3321              } else {                                                                                              
3322                  onlyBindAllApps();                                                                                
3323              }                                                                                                     
3324 +        }                                                                                                         
3325 +                                                                                                                  
3326 +        private void updateIconCache() {                                                                          
3327 +            // Ignore packages which have a promise icon.                                                         
3328 +            HashSet<String> packagesToIgnore = new HashSet<>();                                                   
3329 +            synchronized (sBgLock) {                                                                              
3330 +                for (ItemInfo info : sBgItemsIdMap) {                                                             
3331 +                    if (info instanceof ShortcutInfo) {                                                           
3332 +                        ShortcutInfo si = (ShortcutInfo) info;                                                    
3333 +                        if (si.isPromise() && si.getTargetComponent() != null) {                                  
3334 +                            packagesToIgnore.add(si.getTargetComponent().getPackageName());                       
3335 +                        }                                                                                         
3336 +                    } else if (info instanceof LauncherAppWidgetInfo) {                                           
3337 +                        LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info;                                
3338 +                        if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {                 
3339 +                            packagesToIgnore.add(lawi.providerName.getPackageName());                             
3340 +                        }                                                                                         
3341 +                    }                                                                                             
3342 +                }                                                                                                 
3343 +            }                                                                                                     
3344 +            mIconCache.updateDbIcons(packagesToIgnore);                                                           
3345          }                                                                                                         
3346                                                                                                                    
3347          private void onlyBindAllApps() {                                                                          
3348              final Callbacks oldCallbacks = mCallbacks.get();                                                      
3349              if (oldCallbacks == null) {                                                                           
3350                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
3351                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
3352                  return;                                                                                           
3353              }                                                                                                     
3354                                                                                                                    
3355              // shallow copy                                                                                       
3356              @SuppressWarnings("unchecked")                                                                        
3357              final ArrayList<AppInfo> list                                                                         
3358                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           
3359 +            final WidgetsModel widgetList = mBgWidgetsModel.clone();                                              
3360              Runnable r = new Runnable() {                                                                         
3361                  public void run() {                                                                               
3362                      final long t = SystemClock.uptimeMillis();                                                    
3363                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
3364                      if (callbacks != null) {                                                                      
3365                          callbacks.bindAllApplications(list);                                                      
3366 +                        callbacks.bindAllPackages(widgetList);                                                    
3367                      }                                                                                             
3368                      if (DEBUG_LOADERS) {                                                                          
3369                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
3370                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
3371                      }                                                                                             
3372                  }                                                                                                 
3373              };                                                                                                    
3374              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
3375              if (isRunningOnMainThread) {                                                                          
3376                  r.run();                                                                                          
3377              } else {                                                                                              
3378                  mHandler.post(r);                                                                                 
3379              }                                                                                                     
3380          }                                                                                                         
3381                                                                                                                    
3382          private void loadAllApps() {                                                                              
3383              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
3384                                                                                                                    
3385              final Callbacks oldCallbacks = mCallbacks.get();                                                      
3386              if (oldCallbacks == null) {                                                                           
3387                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
3388                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
3389                  return;                                                                                           
3390              }                                                                                                     
3391                                                                                                                    
3392 -            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
3393 -            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
3394 -                                                                                                                  
3395              final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                               
3396                                                                                                                    
3397              // Clear the list of apps                                                                             
3398              mBgAllAppsList.clear();                                                                               
3399 -            SharedPreferences prefs = mContext.getSharedPreferences(                                              
3400 -                    LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                            
3401              for (UserHandleCompat user : profiles) {                                                              
3402                  // Query for the set of apps                                                                      
3403                  final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                              
3404 -                List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);                
3405 +                final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);          
3406                  if (DEBUG_LOADERS) {                                                                              
3407                      Log.d(TAG, "getActivityList took "                                                            
3408                              + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);                      
3409                      Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);                  
3410                  }                                                                                                 
3411                  // Fail if we don't have any apps                                                                 
3412                  // TODO: Fix this. Only fail for the current user.                                                
3413                  if (apps == null || apps.isEmpty()) {                                                             
3414                      return;                                                                                       
3415                  }                                                                                                 
3416 -                // Sort the applications by name                                                                  
3417 -                final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                             
3418 -                Collections.sort(apps,                                                                            
3419 -                        new LauncherModel.ShortcutNameComparator(mLabelCache));                                   
3420 -                if (DEBUG_LOADERS) {                                                                              
3421 -                    Log.d(TAG, "sort took "                                                                       
3422 -                            + (SystemClock.uptimeMillis()-sortTime) + "ms");                                      
3423 -                }                                                                                                 
3424                                                                                                                    
3425                  // Create the ApplicationInfos                                                                    
3426                  for (int i = 0; i < apps.size(); i++) {                                                           
3427                      LauncherActivityInfoCompat app = apps.get(i);                                                 
3428                      // This builds the icon bitmaps.                                                              
3429 -                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));                
3430 -                }                                                                                                 
3431 -                                                                                                                  
3432 -                if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {             
3433 -                    // Add shortcuts for packages which were installed while launcher was dead.                   
3434 -                    String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                       
3435 -                            + mUserManager.getSerialNumberForUser(user);                                          
3436 -                    Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);       
3437 -                    HashSet<String> newPackageSet = new HashSet<String>();                                        
3438 -                                                                                                                  
3439 -                    for (LauncherActivityInfoCompat info : apps) {                                                
3440 -                        String packageName = info.getComponentName().getPackageName();                            
3441 -                        if (!packagesAdded.contains(packageName)                                                  
3442 -                                && !newPackageSet.contains(packageName)) {                                        
3443 -                            InstallShortcutReceiver.queueInstallShortcut(info, mContext);                         
3444 +                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                             
3445 +                }                                                                                                 
3446 +                                                                                                                  
3447 +                final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);            
3448 +                if (heuristic != null) {                                                                          
3449 +                    runAfterBindCompletes(new Runnable() {                                                        
3450 +                                                                                                                  
3451 +                        @Override                                                                                 
3452 +                        public void run() {                                                                       
3453 +                            heuristic.processUserApps(apps);                                                      
3454                          }                                                                                         
3455 -                        newPackageSet.add(packageName);                                                           
3456 -                    }                                                                                             
3457 -                                                                                                                  
3458 -                    prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                           
3459 +                    });                                                                                           
3460                  }                                                                                                 
3461              }                                                                                                     
3462              // Huh? Shouldn't this be inside the Runnable below?                                                  
3463              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
3464              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
3465                                                                                                                    
3466              // Post callback on main thread                                                                       
3467              mHandler.post(new Runnable() {                                                                        
3468                  public void run() {                                                                               
3469 +                                                                                                                  
3470                      final long bindTime = SystemClock.uptimeMillis();                                             
3471                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
3472                      if (callbacks != null) {                                                                      
3473                          callbacks.bindAllApplications(added);                                                     
3474                          if (DEBUG_LOADERS) {                                                                      
3475                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
3476                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
3477                          }                                                                                         
3478                      } else {                                                                                      
3479                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
3480                      }                                                                                             
3481                  }                                                                                                 
3482              });                                                                                                   
3483 -                                                                                                                  
3484 +            // Cleanup any data stored for a deleted user.                                                        
3485 +            ManagedProfileHeuristic.processAllUsers(profiles, mContext);                                          
3486 +                                                                                                                  
3487 +            loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks),                      
3488 +                    true /* refresh */);                                                                          
3489              if (DEBUG_LOADERS) {                                                                                  
3490                  Log.d(TAG, "Icons processed in "                                                                  
3491                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
3492              }                                                                                                     
3493          }                                                                                                         
3494                                                                                                                    
3495          public void dumpState() {                                                                                 
3496              synchronized (sBgLock) {                                                                              
3497                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
3498 -                Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
3499                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
3500                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
3501                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
3502              }                                                                                                     
3503          }                                                                                                         
3504      }                                                                                                             
3505                                                                                                                    
3506 +    /**                                                                                                           
3507 +     * Called when the icons for packages have been updated in the icon cache.                                    
3508 +     */                                                                                                           
3509 +    public void onPackageIconsUpdated(HashSet<String> updatedPackages, UserHandleCompat user) {                   
3510 +        final Callbacks callbacks = getCallback();                                                                
3511 +        final ArrayList<AppInfo> updatedApps = new ArrayList<>();                                                 
3512 +        final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<>();                                       
3513 +                                                                                                                  
3514 +        // If any package icon has changed (app was updated while launcher was dead),                             
3515 +        // update the corresponding shortcuts.                                                                    
3516 +        synchronized (sBgLock) {                                                                                  
3517 +            for (ItemInfo info : sBgItemsIdMap) {                                                                 
3518 +                if (info instanceof ShortcutInfo && user.equals(info.user)                                        
3519 +                        && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                   
3520 +                    ShortcutInfo si = (ShortcutInfo) info;                                                        
3521 +                    ComponentName cn = si.getTargetComponent();                                                   
3522 +                    if (cn != null && updatedPackages.contains(cn.getPackageName())) {                            
3523 +                        si.updateIcon(mIconCache);                                                                
3524 +                        updatedShortcuts.add(si);                                                                 
3525 +                    }                                                                                             
3526 +                }                                                                                                 
3527 +            }                                                                                                     
3528 +            mBgAllAppsList.updateIconsAndLabels(updatedPackages, user, updatedApps);                              
3529 +        }                                                                                                         
3530 +                                                                                                                  
3531 +        if (!updatedShortcuts.isEmpty()) {                                                                        
3532 +            final UserHandleCompat userFinal = user;                                                              
3533 +            mHandler.post(new Runnable() {                                                                        
3534 +                                                                                                                  
3535 +                public void run() {                                                                               
3536 +                    Callbacks cb = getCallback();                                                                 
3537 +                    if (cb != null && callbacks == cb) {                                                          
3538 +                        cb.bindShortcutsChanged(updatedShortcuts,                                                 
3539 +                                new ArrayList<ShortcutInfo>(), userFinal);                                        
3540 +                    }                                                                                             
3541 +                }                                                                                                 
3542 +            });                                                                                                   
3543 +        }                                                                                                         
3544 +                                                                                                                  
3545 +        if (!updatedApps.isEmpty()) {                                                                             
3546 +            mHandler.post(new Runnable() {                                                                        
3547 +                                                                                                                  
3548 +                public void run() {                                                                               
3549 +                    Callbacks cb = getCallback();                                                                 
3550 +                    if (cb != null && callbacks == cb) {                                                          
3551 +                        cb.bindAppsUpdated(updatedApps);                                                          
3552 +                    }                                                                                             
3553 +                }                                                                                                 
3554 +            });                                                                                                   
3555 +        }                                                                                                         
3556 +                                                                                                                  
3557 +        // Reload widget list. No need to refresh, as we only want to update the icons and labels.                
3558 +        loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false);                                      
3559 +    }                                                                                                             
3560 +                                                                                                                  
3561      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
3562          sWorker.post(task);                                                                                       
3563      }                                                                                                             
3564                                                                                                                    
3565 -    private class AppsAvailabilityCheck extends BroadcastReceiver {                                               
3566 +    @Thunk class AppsAvailabilityCheck extends BroadcastReceiver {                                                
3567                                                                                                                    
3568          @Override                                                                                                 
3569          public void onReceive(Context context, Intent intent) {                                                   
3570              synchronized (sBgLock) {                                                                              
3571                  final LauncherAppsCompat launcherApps = LauncherAppsCompat                                        
3572                          .getInstance(mApp.getContext());                                                          
3573                  final PackageManager manager = context.getPackageManager();                                       
3574                  final ArrayList<String> packagesRemoved = new ArrayList<String>();                                
3575                  final ArrayList<String> packagesUnavailable = new ArrayList<String>();                            
3576                  for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {              
3577                      UserHandleCompat user = entry.getKey();                                                       
3578                      packagesRemoved.clear();                                                                      
3579                      packagesUnavailable.clear();                                                                  
3580                      for (String pkg : entry.getValue()) {                                                         
3581                          if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                                
3582                              boolean packageOnSdcard = launcherApps.isAppEnabled(                                  
3583                                      manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);                       
3584                              if (packageOnSdcard) {                                                                
3585                                  Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);               
3586                                  packagesUnavailable.add(pkg);                                                     
3587                              } else {                                                                              
3588                                  Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);                      
3589                                  packagesRemoved.add(pkg);                                                         
3590                              }                                                                                     
3591                          }                                                                                         
3592                      }                                                                                             
3593                      if (!packagesRemoved.isEmpty()) {                                                             
3594                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,                
3595                                  packagesRemoved.toArray(new String[packagesRemoved.size()]), user));              
3596                      }                                                                                             
3597                      if (!packagesUnavailable.isEmpty()) {                                                         
3598                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,           
3599                                  packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));      
3600                      }                                                                                             
3601                  }                                                                                                 
3602                  sPendingPackages.clear();                                                                         
3603              }                                                                                                     
3604          }                                                                                                         
3605      }                                                                                                             
3606                                                                                                                    
3607      private class PackageUpdatedTask implements Runnable {                                                        
3608          int mOp;                                                                                                  
3609          String[] mPackages;                                                                                       
3610          UserHandleCompat mUser;                                                                                   
3611                                                                                                                    
3612          public static final int OP_NONE = 0;                                                                      
3613          public static final int OP_ADD = 1;                                                                       
3614          public static final int OP_UPDATE = 2;                                                                    
3615          public static final int OP_REMOVE = 3; // uninstlled                                                      
3616          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
3617                                                                                                                    
3618                                                                                                                    
3619          public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                             
3620              mOp = op;                                                                                             
3621              mPackages = packages;                                                                                 
3622              mUser = user;                                                                                         
3623          }                                                                                                         
3624                                                                                                                    
3625          public void run() {                                                                                       
3626 +            if (!mHasLoaderCompletedOnce) {                                                                       
3627 +                // Loader has not yet run.                                                                        
3628 +                return;                                                                                           
3629 +            }                                                                                                     
3630              final Context context = mApp.getContext();                                                            
3631                                                                                                                    
3632              final String[] packages = mPackages;                                                                  
3633              final int N = packages.length;                                                                        
3634              switch (mOp) {                                                                                        
3635 -                case OP_ADD:                                                                                      
3636 +                case OP_ADD: {                                                                                    
3637                      for (int i=0; i<N; i++) {                                                                     
3638                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
3639 -                        mIconCache.remove(packages[i], mUser);                                                    
3640 +                        mIconCache.updateIconsForPkg(packages[i], mUser);                                         
3641                          mBgAllAppsList.addPackage(context, packages[i], mUser);                                   
3642                      }                                                                                             
3643                                                                                                                    
3644 -                    // Auto add shortcuts for added packages.                                                     
3645 -                    if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3646 -                            && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3647 -                        SharedPreferences prefs = context.getSharedPreferences(                                   
3648 -                                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3649 -                        String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3650 -                                + mUserManager.getSerialNumberForUser(mUser);                                     
3651 -                        Set<String> shortcutSet = new HashSet<String>(                                            
3652 -                                prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));                       
3653 -                                                                                                                  
3654 -                        for (int i=0; i<N; i++) {                                                                 
3655 -                            if (!shortcutSet.contains(packages[i])) {                                             
3656 -                                shortcutSet.add(packages[i]);                                                     
3657 -                                List<LauncherActivityInfoCompat> activities =                                     
3658 -                                        mLauncherApps.getActivityList(packages[i], mUser);                        
3659 -                                if (activities != null && !activities.isEmpty()) {                                
3660 -                                    InstallShortcutReceiver.queueInstallShortcut(                                 
3661 -                                            activities.get(0), context);                                          
3662 -                                }                                                                                 
3663 -                            }                                                                                     
3664 -                        }                                                                                         
3665 -                                                                                                                  
3666 -                        prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3667 +                    ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);              
3668 +                    if (heuristic != null) {                                                                      
3669 +                        heuristic.processPackageAdd(mPackages);                                                   
3670                      }                                                                                             
3671                      break;                                                                                        
3672 +                }                                                                                                 
3673                  case OP_UPDATE:                                                                                   
3674                      for (int i=0; i<N; i++) {                                                                     
3675                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               
3676 +                        mIconCache.updateIconsForPkg(packages[i], mUser);                                         
3677                          mBgAllAppsList.updatePackage(context, packages[i], mUser);                                
3678 -                        WidgetPreviewLoader.removePackageFromDb(                                                  
3679 -                                mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3680 +                        mApp.getWidgetCache().removePackage(packages[i], mUser);                                  
3681                      }                                                                                             
3682                      break;                                                                                        
3683 -                case OP_REMOVE:                                                                                   
3684 -                    // Remove the packageName for the set of auto-installed shortcuts. This                       
3685 -                    // will ensure that the shortcut when the app is installed again.                             
3686 -                    if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3687 -                            && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3688 -                        SharedPreferences prefs = context.getSharedPreferences(                                   
3689 -                                LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3690 -                        String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3691 -                                + mUserManager.getSerialNumberForUser(mUser);                                     
3692 -                        HashSet<String> shortcutSet = new HashSet<String>(                                        
3693 -                                prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));                      
3694 -                        shortcutSet.removeAll(Arrays.asList(mPackages));                                          
3695 -                        prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3696 -                    }                                                                                             
3697 -                    // Fall through                                                                               
3698 -                case OP_UNAVAILABLE:                                                                              
3699 -                    boolean clearCache = mOp == OP_REMOVE;                                                        
3700 +                case OP_REMOVE: {                                                                                 
3701 +                    ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);              
3702 +                    if (heuristic != null) {                                                                      
3703 +                        heuristic.processPackageRemoved(mPackages);                                               
3704 +                    }                                                                                             
3705                      for (int i=0; i<N; i++) {                                                                     
3706                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3707 -                        mBgAllAppsList.removePackage(packages[i], mUser, clearCache);                             
3708 -                        WidgetPreviewLoader.removePackageFromDb(                                                  
3709 -                                mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3710 +                        mIconCache.removeIconsForPkg(packages[i], mUser);                                         
3711 +                    }                                                                                             
3712 +                    // Fall through                                                                               
3713 +                }                                                                                                 
3714 +                case OP_UNAVAILABLE:                                                                              
3715 +                    for (int i=0; i<N; i++) {                                                                     
3716 +                        if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3717 +                        mBgAllAppsList.removePackage(packages[i], mUser);                                         
3718 +                        mApp.getWidgetCache().removePackage(packages[i], mUser);                                  
3719                      }                                                                                             
3720                      break;                                                                                        
3721              }                                                                                                     
3722                                                                                                                    
3723              ArrayList<AppInfo> added = null;                                                                      
3724              ArrayList<AppInfo> modified = null;                                                                   
3725              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
3726                                                                                                                    
3727              if (mBgAllAppsList.added.size() > 0) {                                                                
3728                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
3729                  mBgAllAppsList.added.clear();                                                                     
3730              }                                                                                                     
3731              if (mBgAllAppsList.modified.size() > 0) {                                                             
3732                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
3733                  mBgAllAppsList.modified.clear();                                                                  
3734              }                                                                                                     
3735              if (mBgAllAppsList.removed.size() > 0) {                                                              
3736                  removedApps.addAll(mBgAllAppsList.removed);                                                       
3737                  mBgAllAppsList.removed.clear();                                                                   
3738              }                                                                                                     
3739                                                                                                                    
3740              final Callbacks callbacks = getCallback();                                                            
3741              if (callbacks == null) {                                                                              
3742                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
3743                  return;                                                                                           
3744              }                                                                                                     
3745                                                                                                                    
3746              final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                            
3747                      new HashMap<ComponentName, AppInfo>();                                                        
3748                                                                                                                    
3749              if (added != null) {                                                                                  
3750 -                // Ensure that we add all the workspace applications to the db                                    
3751 -                if (LauncherAppState.isDisableAllApps()) {                                                        
3752 -                    final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
3753 -                    addAndBindAddedWorkspaceApps(context, addedInfos);                                            
3754 -                } else {                                                                                          
3755 -                    addAppsToAllApps(context, added);                                                             
3756 -                }                                                                                                 
3757 +                addAppsToAllApps(context, added);                                                                 
3758                  for (AppInfo ai : added) {                                                                        
3759                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3760                  }                                                                                                 
3761              }                                                                                                     
3762                                                                                                                    
3763              if (modified != null) {                                                                               
3764                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
3765                  for (AppInfo ai : modified) {                                                                     
3766                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3767                  }                                                                                                 
3768                                                                                                                    
3769                  mHandler.post(new Runnable() {                                                                    
3770                      public void run() {                                                                           
3771                          Callbacks cb = getCallback();                                                             
3772                          if (callbacks == cb && cb != null) {                                                      
3773                              callbacks.bindAppsUpdated(modifiedFinal);                                             
3774                          }                                                                                         
3775                      }                                                                                             
3776                  });                                                                                               
3777              }                                                                                                     
3778                                                                                                                    
3779              // Update shortcut infos                                                                              
3780              if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                              
3781                  final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();                   
3782                  final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();                   
3783                  final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();          
3784                                                                                                                    
3785                  HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));                        
3786                  synchronized (sBgLock) {                                                                          
3787 -                    for (ItemInfo info : sBgItemsIdMap.values()) {                                                
3788 +                    for (ItemInfo info : sBgItemsIdMap) {                                                         
3789                          if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                            
3790                              ShortcutInfo si = (ShortcutInfo) info;                                                
3791                              boolean infoUpdated = false;                                                          
3792                              boolean shortcutUpdated = false;                                                      
3793                                                                                                                    
3794                              // Update shortcuts which use iconResource.                                           
3795                              if ((si.iconResource != null)                                                         
3796                                      && packageSet.contains(si.iconResource.packageName)) {                        
3797 -                                Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,             
3798 -                                        si.iconResource.resourceName, mIconCache, context);                       
3799 +                                Bitmap icon = Utilities.createIconBitmap(                                         
3800 +                                        si.iconResource.packageName,                                              
3801 +                                        si.iconResource.resourceName, context);                                   
3802                                  if (icon != null) {                                                               
3803                                      si.setIcon(icon);                                                             
3804                                      si.usingFallbackIcon = false;                                                 
3805                                      infoUpdated = true;                                                           
3806                                  }                                                                                 
3807                              }                                                                                     
3808                                                                                                                    
3809                              ComponentName cn = si.getTargetComponent();                                           
3810                              if (cn != null && packageSet.contains(cn.getPackageName())) {                         
3811                                  AppInfo appInfo = addedOrUpdatedApps.get(cn);                                     
3812                                                                                                                    
3813                                  if (si.isPromise()) {                                                             
3814 -                                    mIconCache.deletePreloadedIcon(cn, mUser);                                    
3815                                      if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                    
3816                                          // Auto install icon                                                      
3817                                          PackageManager pm = context.getPackageManager();                          
3818                                          ResolveInfo matched = pm.resolveActivity(                                 
3819                                                  new Intent(Intent.ACTION_MAIN)                                    
3820                                                  .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),          
3821                                                  PackageManager.MATCH_DEFAULT_ONLY);                               
3822                                          if (matched == null) {                                                    
3823                                              // Try to find the best match activity.                               
3824                                              Intent intent = pm.getLaunchIntentForPackage(                         
3825                                                      cn.getPackageName());                                         
3826                                              if (intent != null) {                                                 
3827                                                  cn = intent.getComponent();                                       
3828                                                  appInfo = addedOrUpdatedApps.get(cn);                             
3829                                              }                                                                     
3830                                                                                                                    
3831                                              if ((intent == null) || (appInfo == null)) {                          
3832                                                  removedShortcuts.add(si);                                         
3833                                                  continue;                                                         
3834                                              }                                                                     
3835                                              si.promisedIntent = intent;                                           
3836                                          }                                                                         
3837                                      }                                                                             
3838                                                                                                                    
3839                                      // Restore the shortcut.                                                      
3840 +                                    if (appInfo != null) {                                                        
3841 +                                        si.flags = appInfo.flags;                                                 
3842 +                                    }                                                                             
3843 +                                                                                                                  
3844                                      si.intent = si.promisedIntent;                                                
3845                                      si.promisedIntent = null;                                                     
3846 -                                    si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                                 
3847 -                                            & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                  
3848 -                                            & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                          
3849 -                                                                                                                  
3850 +                                    si.status = ShortcutInfo.DEFAULT;                                             
3851                                      infoUpdated = true;                                                           
3852                                      si.updateIcon(mIconCache);                                                    
3853                                  }                                                                                 
3854                                                                                                                    
3855                                  if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())           
3856                                          && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {     
3857                                      si.updateIcon(mIconCache);                                                    
3858 -                                    si.title = appInfo.title.toString();                                          
3859 +                                    si.title = Utilities.trim(appInfo.title);                                     
3860                                      si.contentDescription = appInfo.contentDescription;                           
3861                                      infoUpdated = true;                                                           
3862                                  }                                                                                 
3863                                                                                                                    
3864                                  if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {            
3865                                      // Since package was just updated, the target must be available now.          
3866                                      si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                   
3867                                      shortcutUpdated = true;                                                       
3868                                  }                                                                                 
3869                              }                                                                                     
3870                                                                                                                    
3871                              if (infoUpdated || shortcutUpdated) {                                                 
3872                                  updatedShortcuts.add(si);                                                         
3873                              }                                                                                     
3874                              if (infoUpdated) {                                                                    
3875                                  updateItemInDatabase(context, si);                                                
3876                              }                                                                                     
3877                          } else if (info instanceof LauncherAppWidgetInfo) {                                       
3878                              LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                      
3879                              if (mUser.equals(widgetInfo.user)                                                     
3880                                      && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)   
3881                                      && packageSet.contains(widgetInfo.providerName.getPackageName())) {           
3882                                  widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;       
3883                                  widgets.add(widgetInfo);                                                          
3884                                  updateItemInDatabase(context, widgetInfo);                                        
3885                              }                                                                                     
3886                          }                                                                                         
3887                      }                                                                                             
3888                  }                                                                                                 
3889                                                                                                                    
3890                  if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                                 
3891                      mHandler.post(new Runnable() {                                                                
3892                                                                                                                    
3893                          public void run() {                                                                       
3894                              Callbacks cb = getCallback();                                                         
3895                              if (callbacks == cb && cb != null) {                                                  
3896                                  callbacks.bindShortcutsChanged(                                                   
3897                                          updatedShortcuts, removedShortcuts, mUser);                               
3898                              }                                                                                     
3899                          }                                                                                         
3900                      });                                                                                           
3901                      if (!removedShortcuts.isEmpty()) {                                                            
3902                          deleteItemsFromDatabase(context, removedShortcuts);                                       
3903                      }                                                                                             
3904                  }                                                                                                 
3905                  if (!widgets.isEmpty()) {                                                                         
3906                      mHandler.post(new Runnable() {                                                                
3907                          public void run() {                                                                       
3908                              Callbacks cb = getCallback();                                                         
3909                              if (callbacks == cb && cb != null) {                                                  
3910                                  callbacks.bindWidgetsRestored(widgets);                                           
3911                              }                                                                                     
3912                          }                                                                                         
3913                      });                                                                                           
3914                  }                                                                                                 
3915              }                                                                                                     
3916                                                                                                                    
3917              final ArrayList<String> removedPackageNames =                                                         
3918                      new ArrayList<String>();                                                                      
3919              if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                                      
3920                  // Mark all packages in the broadcast to be removed                                               
3921                  removedPackageNames.addAll(Arrays.asList(packages));                                              
3922              } else if (mOp == OP_UPDATE) {                                                                        
3923                  // Mark disabled packages in the broadcast to be removed                                          
3924                  for (int i=0; i<N; i++) {                                                                         
3925                      if (isPackageDisabled(context, packages[i], mUser)) {                                         
3926                          removedPackageNames.add(packages[i]);                                                     
3927                      }                                                                                             
3928                  }                                                                                                 
3929              }                                                                                                     
3930                                                                                                                    
3931              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
3932                  final int removeReason;                                                                           
3933                  if (mOp == OP_UNAVAILABLE) {                                                                      
3934                      removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                                      
3935                  } else {                                                                                          
3936                      // Remove all the components associated with this package                                     
3937                      for (String pn : removedPackageNames) {                                                       
3938                          deletePackageFromDatabase(context, pn, mUser);                                            
3939                      }                                                                                             
3940                      // Remove all the specific components                                                         
3941                      for (AppInfo a : removedApps) {                                                               
3942                          ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);          
3943                          deleteItemsFromDatabase(context, infos);                                                  
3944                      }                                                                                             
3945                      removeReason = 0;                                                                             
3946                  }                                                                                                 
3947                                                                                                                    
3948                  // Remove any queued items from the install queue                                                 
3949                  InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);              
3950                  // Call the components-removed callback                                                           
3951                  mHandler.post(new Runnable() {                                                                    
3952                      public void run() {                                                                           
3953                          Callbacks cb = getCallback();                                                             
3954                          if (callbacks == cb && cb != null) {                                                      
3955                              callbacks.bindComponentsRemoved(                                                      
3956                                      removedPackageNames, removedApps, mUser, removeReason);                       
3957                          }                                                                                         
3958                      }                                                                                             
3959                  });                                                                                               
3960              }                                                                                                     
3961 -            if (Build.VERSION.SDK_INT < 17) {                                                                     
3962 -                loadAndBindWidgetsAndShortcuts(context, callbacks);                                               
3963 -            }                                                                                                     
3964 +                                                                                                                  
3965 +            // onProvidersChanged method (API >= 17) already refreshed the widget list                            
3966 +            loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17);                       
3967 +                                                                                                                  
3968              // Write all the logs to disk                                                                         
3969              mHandler.post(new Runnable() {                                                                        
3970                  public void run() {                                                                               
3971                      Callbacks cb = getCallback();                                                                 
3972                      if (callbacks == cb && cb != null) {                                                          
3973                          callbacks.dumpLogsToLocalData();                                                          
3974                      }                                                                                             
3975                  }                                                                                                 
3976              });                                                                                                   
3977          }                                                                                                         
3978      }                                                                                                             
3979                                                                                                                    
3980      public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,                         
3981              boolean refresh) {                                                                                    
3982          ArrayList<LauncherAppWidgetProviderInfo> results =                                                        
3983                  new ArrayList<LauncherAppWidgetProviderInfo>();                                                   
3984          try {                                                                                                     
3985              synchronized (sBgLock) {                                                                              
3986                  if (sBgWidgetProviders == null || refresh) {                                                      
3987                      HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders                       
3988                              = new HashMap<>();                                                                    
3989                      AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);                      
3990                      LauncherAppWidgetProviderInfo info;                                                           
3991                                                                                                                    
3992                      List<AppWidgetProviderInfo> widgets = wm.getAllProviders();                                   
3993                      for (AppWidgetProviderInfo pInfo : widgets) {                                                 
3994                          info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                    
3995                          UserHandleCompat user = wm.getUser(info);                                                 
3996                          tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);                      
3997                      }                                                                                             
3998                                                                                                                    
3999                      Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();          
4000                      for (CustomAppWidget widget : customWidgets) {                                                
4001                          info = new LauncherAppWidgetProviderInfo(context, widget);                                
4002                          UserHandleCompat user = wm.getUser(info);                                                 
4003                          tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);                      
4004                      }                                                                                             
4005                      // Replace the global list at the very end, so that if there is an exception,                 
4006                      // previously loaded provider list is used.                                                   
4007                      sBgWidgetProviders = tmpWidgetProviders;                                                      
4008                  }                                                                                                 
4009                  results.addAll(sBgWidgetProviders.values());                                                      
4010                  return results;                                                                                   
4011              }                                                                                                     
4012          } catch (Exception e) {                                                                                   
4013              if (e.getCause() instanceof TransactionTooLargeException) {                                           
4014                  // the returned value may be incomplete and will not be refreshed until the next                  
4015                  // time Launcher starts.                                                                          
4016                  // TODO: after figuring out a repro step, introduce a dirty bit to check when                     
4017                  // onResume is called to refresh the widget provider list.                                        
4018                  synchronized (sBgLock) {                                                                          
4019                      if (sBgWidgetProviders != null) {                                                             
4020                          results.addAll(sBgWidgetProviders.values());                                              
4021                      }                                                                                             
4022                      return results;                                                                               
4023                  }                                                                                                 
4024              } else {                                                                                              
4025                  throw e;                                                                                          
4026              }                                                                                                     
4027          }                                                                                                         
4028      }                                                                                                             
4029                                                                                                                    
4030      public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,                  
4031              UserHandleCompat user) {                                                                              
4032          synchronized (sBgLock) {                                                                                  
4033              if (sBgWidgetProviders == null) {                                                                     
4034                  getWidgetProviders(ctx, false /* refresh */);                                                     
4035              }                                                                                                     
4036              return sBgWidgetProviders.get(new ComponentKey(name, user));                                          
4037          }                                                                                                         
4038      }                                                                                                             
4039                                                                                                                    
4040 -    public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks) {                
4041 -        runOnWorkerThread(new Runnable(){                                                                         
4042 +    public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks,                  
4043 +            final boolean refresh) {                                                                              
4044 +                                                                                                                  
4045 +        runOnWorkerThread(new Runnable() {                                                                        
4046              @Override                                                                                             
4047              public void run() {                                                                                   
4048 -                final ArrayList<Object> list =                                                                    
4049 -                        getSortedWidgetsAndShortcuts(context, true /* refresh */);                                
4050 +                updateWidgetsModel(context, refresh);                                                             
4051 +                final WidgetsModel model = mBgWidgetsModel.clone();                                               
4052 +                                                                                                                  
4053                  mHandler.post(new Runnable() {                                                                    
4054                      @Override                                                                                     
4055                      public void run() {                                                                           
4056                          Callbacks cb = getCallback();                                                             
4057                          if (callbacks == cb && cb != null) {                                                      
4058 -                            callbacks.bindPackagesUpdated(list);                                                  
4059 +                            callbacks.bindAllPackages(model);                                                     
4060                          }                                                                                         
4061                      }                                                                                             
4062                  });                                                                                               
4063 +                // update the Widget entries inside DB on the worker thread.                                      
4064 +                LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(                           
4065 +                        model.getRawList());                                                                      
4066              }                                                                                                     
4067          });                                                                                                       
4068      }                                                                                                             
4069                                                                                                                    
4070 -    // Returns a list of ResolveInfos/AppWidgetInfos in sorted order                                              
4071 -    public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context, boolean refresh) {              
4072 +    /**                                                                                                           
4073 +     * Returns a list of ResolveInfos/AppWidgetInfos.                                                             
4074 +     *                                                                                                            
4075 +     * @see #loadAndBindWidgetsAndShortcuts                                                                       
4076 +     */                                                                                                           
4077 +    @Thunk void updateWidgetsModel(Context context, boolean refresh) {                                            
4078          PackageManager packageManager = context.getPackageManager();                                              
4079          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
4080          widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));                                         
4081          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
4082          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
4083 -        Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));                      
4084 -        return widgetsAndShortcuts;                                                                               
4085 -    }                                                                                                             
4086 -                                                                                                                  
4087 -    private static boolean isPackageDisabled(Context context, String packageName,                                 
4088 +        mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts);                                              
4089 +    }                                                                                                             
4090 +                                                                                                                  
4091 +    @Thunk static boolean isPackageDisabled(Context context, String packageName,                                  
4092              UserHandleCompat user) {                                                                              
4093          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
4094          return !launcherApps.isPackageEnabledForProfile(packageName, user);                                       
4095      }                                                                                                             
4096                                                                                                                    
4097      public static boolean isValidPackageActivity(Context context, ComponentName cn,                               
4098              UserHandleCompat user) {                                                                              
4099          if (cn == null) {                                                                                         
4100              return false;                                                                                         
4101          }                                                                                                         
4102          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
4103          if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                                
4104              return false;                                                                                         
4105          }                                                                                                         
4106          return launcherApps.isActivityEnabledForProfile(cn, user);                                                
4107      }                                                                                                             
4108                                                                                                                    
4109      public static boolean isValidPackage(Context context, String packageName,                                     
4110              UserHandleCompat user) {                                                                              
4111          if (packageName == null) {                                                                                
4112              return false;                                                                                         
4113          }                                                                                                         
4114          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
4115          return launcherApps.isPackageEnabledForProfile(packageName, user);                                        
4116      }                                                                                                             
4117                                                                                                                    
4118      /**                                                                                                           
4119       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
4120       * to a package that is not yet installed on the system.                                                      
4121       */                                                                                                           
4122 -    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                         
4123 -            int promiseType) {                                                                                    
4124 +    public ShortcutInfo getRestoredItemInfo(Cursor c, int titleIndex, Intent intent,                              
4125 +            int promiseType, int itemType, CursorIconInfo iconInfo, Context context) {                            
4126          final ShortcutInfo info = new ShortcutInfo();                                                             
4127          info.user = UserHandleCompat.myUserHandle();                                                              
4128 -        mIconCache.getTitleAndIcon(info, intent, info.user, true);                                                
4129 +                                                                                                                  
4130 +        Bitmap icon = iconInfo.loadIcon(c, info, context);                                                        
4131 +        // the fallback icon                                                                                      
4132 +        if (icon == null) {                                                                                       
4133 +            mIconCache.getTitleAndIcon(info, intent, info.user, false /* useLowResIcon */);                       
4134 +        } else {                                                                                                  
4135 +            info.setIcon(icon);                                                                                   
4136 +        }                                                                                                         
4137                                                                                                                    
4138          if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                               
4139 -            String title = (cursor != null) ? cursor.getString(titleIndex) : null;                                
4140 +            String title = (c != null) ? c.getString(titleIndex) : null;                                          
4141              if (!TextUtils.isEmpty(title)) {                                                                      
4142 -                info.title = title;                                                                               
4143 -            }                                                                                                     
4144 -            info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                                        
4145 +                info.title = Utilities.trim(title);                                                               
4146 +            }                                                                                                     
4147          } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                                     
4148              if (TextUtils.isEmpty(info.title)) {                                                                  
4149 -                info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                                
4150 -            }                                                                                                     
4151 -            info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                                      
4152 +                info.title = (c != null) ? Utilities.trim(c.getString(titleIndex)) : "";                          
4153 +            }                                                                                                     
4154          } else {                                                                                                  
4155              throw new InvalidParameterException("Invalid restoreType " + promiseType);                            
4156          }                                                                                                         
4157                                                                                                                    
4158 -        info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
4159 -                info.title.toString(), info.user);                                                                
4160 -        info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
4161 +        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);                      
4162 +        info.itemType = itemType;                                                                                 
4163          info.promisedIntent = intent;                                                                             
4164 +        info.status = promiseType;                                                                                
4165          return info;                                                                                              
4166      }                                                                                                             
4167                                                                                                                    
4168      /**                                                                                                           
4169       * Make an Intent object for a restored application or shortcut item that points                              
4170       * to the market page for the item.                                                                           
4171       */                                                                                                           
4172 -    private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              
4173 +    @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                               
4174          ComponentName componentName = intent.getComponent();                                                      
4175          return getMarketIntent(componentName.getPackageName());                                                   
4176      }                                                                                                             
4177                                                                                                                    
4178      static Intent getMarketIntent(String packageName) {                                                           
4179          return new Intent(Intent.ACTION_VIEW)                                                                     
4180              .setData(new Uri.Builder()                                                                            
4181                  .scheme("market")                                                                                 
4182                  .authority("details")                                                                             
4183                  .appendQueryParameter("id", packageName)                                                          
4184                  .build());                                                                                        
4185      }                                                                                                             
4186                                                                                                                    
4187      /**                                                                                                           
4188 -     * This is called from the code that adds shortcuts from the intent receiver.  This                           
4189 -     * doesn't have a Cursor, but                                                                                 
4190 -     */                                                                                                           
4191 -    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
4192 -            UserHandleCompat user, Context context) {                                                             
4193 -        return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);                        
4194 -    }                                                                                                             
4195 -                                                                                                                  
4196 -    /**                                                                                                           
4197       * Make an ShortcutInfo object for a shortcut that is an application.                                         
4198       *                                                                                                            
4199       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
4200       */                                                                                                           
4201 -    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
4202 +    public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                                 
4203              UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,                      
4204 -            HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {                               
4205 +            boolean allowMissingTarget, boolean useLowResIcon) {                                                  
4206          if (user == null) {                                                                                       
4207              Log.d(TAG, "Null user found in getShortcutInfo");                                                     
4208              return null;                                                                                          
4209          }                                                                                                         
4210                                                                                                                    
4211          ComponentName componentName = intent.getComponent();                                                      
4212          if (componentName == null) {                                                                              
4213              Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                           
4214              return null;                                                                                          
4215          }                                                                                                         
4216                                                                                                                    
4217          Intent newIntent = new Intent(intent.getAction(), null);                                                  
4218          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
4219          newIntent.setComponent(componentName);                                                                    
4220          LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                          
4221          if ((lai == null) && !allowMissingTarget) {                                                               
4222              Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                            
4223              return null;                                                                                          
4224          }                                                                                                         
4225                                                                                                                    
4226          final ShortcutInfo info = new ShortcutInfo();                                                             
4227 -                                                                                                                  
4228 -        // the resource -- This may implicitly give us back the fallback icon,                                    
4229 -        // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
4230 -        // to avoid saving lots of copies of that in the database, and most apps                                  
4231 -        // have icons anyway.                                                                                     
4232 -        Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);                                         
4233 -                                                                                                                  
4234 -        // the db                                                                                                 
4235 -        if (icon == null) {                                                                                       
4236 -            if (c != null) {                                                                                      
4237 -                icon = getIconFromCursor(c, iconIndex, context);                                                  
4238 -            }                                                                                                     
4239 -        }                                                                                                         
4240 -        // the fallback icon                                                                                      
4241 -        if (icon == null) {                                                                                       
4242 -            icon = mIconCache.getDefaultIcon(user);                                                               
4243 -            info.usingFallbackIcon = true;                                                                        
4244 -        }                                                                                                         
4245 -        info.setIcon(icon);                                                                                       
4246 -                                                                                                                  
4247 -        // From the cache.                                                                                        
4248 -        if (labelCache != null) {                                                                                 
4249 -            info.title = labelCache.get(componentName);                                                           
4250 -        }                                                                                                         
4251 -                                                                                                                  
4252 -        // from the resource                                                                                      
4253 -        if (info.title == null && lai != null) {                                                                  
4254 -            info.title = lai.getLabel();                                                                          
4255 -            if (labelCache != null) {                                                                             
4256 -                labelCache.put(componentName, info.title);                                                        
4257 -            }                                                                                                     
4258 -        }                                                                                                         
4259 +        mIconCache.getTitleAndIcon(info, componentName, lai, user, false, useLowResIcon);                         
4260 +        if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                              
4261 +            Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                                      
4262 +            info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                                  
4263 +        }                                                                                                         
4264 +                                                                                                                  
4265          // from the db                                                                                            
4266 -        if (info.title == null) {                                                                                 
4267 -            if (c != null) {                                                                                      
4268 -                info.title =  c.getString(titleIndex);                                                            
4269 -            }                                                                                                     
4270 -        }                                                                                                         
4271 +        if (TextUtils.isEmpty(info.title) && c != null) {                                                         
4272 +            info.title =  Utilities.trim(c.getString(titleIndex));                                                
4273 +        }                                                                                                         
4274 +                                                                                                                  
4275          // fall back to the class name of the activity                                                            
4276          if (info.title == null) {                                                                                 
4277              info.title = componentName.getClassName();                                                            
4278          }                                                                                                         
4279 +                                                                                                                  
4280          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
4281          info.user = user;                                                                                         
4282 -        info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
4283 -                info.title.toString(), info.user);                                                                
4284 +        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);                      
4285 +        if (lai != null) {                                                                                        
4286 +            info.flags = AppInfo.initFlags(lai);                                                                  
4287 +        }                                                                                                         
4288          return info;                                                                                              
4289      }                                                                                                             
4290                                                                                                                    
4291 -    static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        
4292 +    static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,                                          
4293              ItemInfoFilter f) {                                                                                   
4294          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
4295          for (ItemInfo i : infos) {                                                                                
4296              if (i instanceof ShortcutInfo) {                                                                      
4297                  ShortcutInfo info = (ShortcutInfo) i;                                                             
4298                  ComponentName cn = info.getTargetComponent();                                                     
4299                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
4300                      filtered.add(info);                                                                           
4301                  }                                                                                                 
4302              } else if (i instanceof FolderInfo) {                                                                 
4303                  FolderInfo info = (FolderInfo) i;                                                                 
4304                  for (ShortcutInfo s : info.contents) {                                                            
4305                      ComponentName cn = s.getTargetComponent();                                                    
4306                      if (cn != null && f.filterItem(info, s, cn)) {                                                
4307                          filtered.add(s);                                                                          
4308                      }                                                                                             
4309                  }                                                                                                 
4310              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
4311                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
4312                  ComponentName cn = info.providerName;                                                             
4313                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
4314                      filtered.add(info);                                                                           
4315                  }                                                                                                 
4316              }                                                                                                     
4317          }                                                                                                         
4318          return new ArrayList<ItemInfo>(filtered);                                                                 
4319      }                                                                                                             
4320                                                                                                                    
4321 -    private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                            
4322 +    @Thunk ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                             
4323              final UserHandleCompat user) {                                                                        
4324          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
4325              @Override                                                                                             
4326              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
4327                  if (info.user == null) {                                                                          
4328                      return cn.equals(cname);                                                                      
4329                  } else {                                                                                          
4330                      return cn.equals(cname) && info.user.equals(user);                                            
4331                  }                                                                                                 
4332              }                                                                                                     
4333          };                                                                                                        
4334 -        return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
4335 +        return filterItemInfos(sBgItemsIdMap, filter);                                                            
4336      }                                                                                                             
4337                                                                                                                    
4338      /**                                                                                                           
4339       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
4340       */                                                                                                           
4341 -    private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
4342 -            int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
4343 -            int titleIndex) {                                                                                     
4344 -                                                                                                                  
4345 -        Bitmap icon = null;                                                                                       
4346 +    @Thunk ShortcutInfo getShortcutInfo(Cursor c, Context context,                                                
4347 +            int titleIndex, CursorIconInfo iconInfo) {                                                            
4348          final ShortcutInfo info = new ShortcutInfo();                                                             
4349          // Non-app shortcuts are only supported for current user.                                                 
4350          info.user = UserHandleCompat.myUserHandle();                                                              
4351          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
4352                                                                                                                    
4353          // TODO: If there's an explicit component and we can't install that, delete it.                           
4354                                                                                                                    
4355 -        info.title = c.getString(titleIndex);                                                                     
4356 -                                                                                                                  
4357 -        int iconType = c.getInt(iconTypeIndex);                                                                   
4358 -        switch (iconType) {                                                                                       
4359 -        case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
4360 -            String packageName = c.getString(iconPackageIndex);                                                   
4361 -            String resourceName = c.getString(iconResourceIndex);                                                 
4362 -            info.customIcon = false;                                                                              
4363 -            // the resource                                                                                       
4364 -            icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);                    
4365 -            // the db                                                                                             
4366 -            if (icon == null) {                                                                                   
4367 -                icon = getIconFromCursor(c, iconIndex, context);                                                  
4368 -            }                                                                                                     
4369 -            // the fallback icon                                                                                  
4370 -            if (icon == null) {                                                                                   
4371 -                icon = mIconCache.getDefaultIcon(info.user);                                                      
4372 -                info.usingFallbackIcon = true;                                                                    
4373 -            }                                                                                                     
4374 -            break;                                                                                                
4375 -        case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
4376 -            icon = getIconFromCursor(c, iconIndex, context);                                                      
4377 -            if (icon == null) {                                                                                   
4378 -                icon = mIconCache.getDefaultIcon(info.user);                                                      
4379 -                info.customIcon = false;                                                                          
4380 -                info.usingFallbackIcon = true;                                                                    
4381 -            } else {                                                                                              
4382 -                info.customIcon = true;                                                                           
4383 -            }                                                                                                     
4384 -            break;                                                                                                
4385 -        default:                                                                                                  
4386 +        info.title = Utilities.trim(c.getString(titleIndex));                                                     
4387 +                                                                                                                  
4388 +        Bitmap icon = iconInfo.loadIcon(c, info, context);                                                        
4389 +        // the fallback icon                                                                                      
4390 +        if (icon == null) {                                                                                       
4391              icon = mIconCache.getDefaultIcon(info.user);                                                          
4392              info.usingFallbackIcon = true;                                                                        
4393 -            info.customIcon = false;                                                                              
4394 -            break;                                                                                                
4395          }                                                                                                         
4396          info.setIcon(icon);                                                                                       
4397          return info;                                                                                              
4398 -    }                                                                                                             
4399 -                                                                                                                  
4400 -    Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
4401 -        @SuppressWarnings("all") // suppress dead code warning                                                    
4402 -        final boolean debug = false;                                                                              
4403 -        if (debug) {                                                                                              
4404 -            Log.d(TAG, "getIconFromCursor app="                                                                   
4405 -                    + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
4406 -        }                                                                                                         
4407 -        byte[] data = c.getBlob(iconIndex);                                                                       
4408 -        try {                                                                                                     
4409 -            return Utilities.createIconBitmap(                                                                    
4410 -                    BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
4411 -        } catch (Exception e) {                                                                                   
4412 -            return null;                                                                                          
4413 -        }                                                                                                         
4414      }                                                                                                             
4415                                                                                                                    
4416      ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                           
4417          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
4418          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
4419          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
4420                                                                                                                    
4421          if (intent == null) {                                                                                     
4422              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
4423              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
4424              return null;                                                                                          
4425          }                                                                                                         
4426                                                                                                                    
4427          Bitmap icon = null;                                                                                       
4428          boolean customIcon = false;                                                                               
4429          ShortcutIconResource iconResource = null;                                                                 
4430                                                                                                                    
4431          if (bitmap instanceof Bitmap) {                                                                           
4432              icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                          
4433              customIcon = true;                                                                                    
4434          } else {                                                                                                  
4435              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
4436              if (extra instanceof ShortcutIconResource) {                                                          
4437                  iconResource = (ShortcutIconResource) extra;                                                      
4438                  icon = Utilities.createIconBitmap(iconResource.packageName,                                       
4439 -                        iconResource.resourceName, mIconCache, context);                                          
4440 +                        iconResource.resourceName, context);                                                      
4441              }                                                                                                     
4442          }                                                                                                         
4443                                                                                                                    
4444          final ShortcutInfo info = new ShortcutInfo();                                                             
4445                                                                                                                    
4446          // Only support intents for current user for now. Intents sent from other                                 
4447          // users wouldn't get here without intent forwarding anyway.                                              
4448          info.user = UserHandleCompat.myUserHandle();                                                              
4449          if (icon == null) {                                                                                       
4450              icon = mIconCache.getDefaultIcon(info.user);                                                          
4451              info.usingFallbackIcon = true;                                                                        
4452          }                                                                                                         
4453          info.setIcon(icon);                                                                                       
4454                                                                                                                    
4455 -        info.title = name;                                                                                        
4456 -        info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
4457 -                info.title.toString(), info.user);                                                                
4458 +        info.title = Utilities.trim(name);                                                                        
4459 +        info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);                      
4460          info.intent = intent;                                                                                     
4461          info.customIcon = customIcon;                                                                             
4462          info.iconResource = iconResource;                                                                         
4463                                                                                                                    
4464          return info;                                                                                              
4465 -    }                                                                                                             
4466 -                                                                                                                  
4467 -    boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
4468 -            int iconIndex) {                                                                                      
4469 -        // If apps can't be on SD, don't even bother.                                                             
4470 -        if (!mAppsCanBeOnRemoveableStorage) {                                                                     
4471 -            return false;                                                                                         
4472 -        }                                                                                                         
4473 -        // If this icon doesn't have a custom icon, check to see                                                  
4474 -        // what's stored in the DB, and if it doesn't match what                                                  
4475 -        // we're going to show, store what we are going to show back                                              
4476 -        // into the DB.  We do this so when we're loading, if the                                                 
4477 -        // package manager can't find an icon (for example because                                                
4478 -        // the app is on SD) then we can use that instead.                                                        
4479 -        if (!info.customIcon && !info.usingFallbackIcon) {                                                        
4480 -            cache.put(info, c.getBlob(iconIndex));                                                                
4481 -            return true;                                                                                          
4482 -        }                                                                                                         
4483 -        return false;                                                                                             
4484 -    }                                                                                                             
4485 -    void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
4486 -        boolean needSave = false;                                                                                 
4487 -        try {                                                                                                     
4488 -            if (data != null) {                                                                                   
4489 -                Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
4490 -                Bitmap loaded = info.getIcon(mIconCache);                                                         
4491 -                needSave = !saved.sameAs(loaded);                                                                 
4492 -            } else {                                                                                              
4493 -                needSave = true;                                                                                  
4494 -            }                                                                                                     
4495 -        } catch (Exception e) {                                                                                   
4496 -            needSave = true;                                                                                      
4497 -        }                                                                                                         
4498 -        if (needSave) {                                                                                           
4499 -            Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
4500 -            // This is slower than is ideal, but this only happens once                                           
4501 -            // or when the app is updated with a new icon.                                                        
4502 -            updateItemInDatabase(context, info);                                                                  
4503 -        }                                                                                                         
4504      }                                                                                                             
4505                                                                                                                    
4506      /**                                                                                                           
4507       * Return an existing FolderInfo object if we have encountered this ID previously,                            
4508       * or make a new one.                                                                                         
4509       */                                                                                                           
4510 -    private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      
4511 +    @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {                        
4512          // See if a placeholder was created for us already                                                        
4513          FolderInfo folderInfo = folders.get(id);                                                                  
4514          if (folderInfo == null) {                                                                                 
4515              // No placeholder -- create a new instance                                                            
4516              folderInfo = new FolderInfo();                                                                        
4517              folders.put(id, folderInfo);                                                                          
4518          }                                                                                                         
4519          return folderInfo;                                                                                        
4520      }                                                                                                             
4521                                                                                                                    
4522 -    public static final Comparator<AppInfo> getAppNameComparator() {                                              
4523 -        final Collator collator = Collator.getInstance();                                                         
4524 -        return new Comparator<AppInfo>() {                                                                        
4525 -            public final int compare(AppInfo a, AppInfo b) {                                                      
4526 -                if (a.user.equals(b.user)) {                                                                      
4527 -                    int result = collator.compare(a.title.toString().trim(),                                      
4528 -                            b.title.toString().trim());                                                           
4529 -                    if (result == 0) {                                                                            
4530 -                        result = a.componentName.compareTo(b.componentName);                                      
4531 -                    }                                                                                             
4532 -                    return result;                                                                                
4533 -                } else {                                                                                          
4534 -                    // TODO Need to figure out rules for sorting                                                  
4535 -                    // profiles, this puts work second.                                                           
4536 -                    return a.user.toString().compareTo(b.user.toString());                                        
4537 -                }                                                                                                 
4538 -            }                                                                                                     
4539 -        };                                                                                                        
4540 -    }                                                                                                             
4541 -    public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
4542 -            = new Comparator<AppInfo>() {                                                                         
4543 -        public final int compare(AppInfo a, AppInfo b) {                                                          
4544 -            if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
4545 -            if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
4546 -            return 0;                                                                                             
4547 -        }                                                                                                         
4548 -    };                                                                                                            
4549 -    static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
4550 -        if (info.activityInfo != null) {                                                                          
4551 -            return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
4552 -        } else {                                                                                                  
4553 -            return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
4554 -        }                                                                                                         
4555 -    }                                                                                                             
4556 -    public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {                
4557 -        private Collator mCollator;                                                                               
4558 -        private HashMap<Object, CharSequence> mLabelCache;                                                        
4559 -        ShortcutNameComparator(PackageManager pm) {                                                               
4560 -            mLabelCache = new HashMap<Object, CharSequence>();                                                    
4561 -            mCollator = Collator.getInstance();                                                                   
4562 -        }                                                                                                         
4563 -        ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {                                        
4564 -            mLabelCache = labelCache;                                                                             
4565 -            mCollator = Collator.getInstance();                                                                   
4566 -        }                                                                                                         
4567 -        public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {                    
4568 -            String labelA, labelB;                                                                                
4569 -            ComponentName keyA = a.getComponentName();                                                            
4570 -            ComponentName keyB = b.getComponentName();                                                            
4571 -            if (mLabelCache.containsKey(keyA)) {                                                                  
4572 -                labelA = mLabelCache.get(keyA).toString();                                                        
4573 -            } else {                                                                                              
4574 -                labelA = a.getLabel().toString().trim();                                                          
4575 -                                                                                                                  
4576 -                mLabelCache.put(keyA, labelA);                                                                    
4577 -            }                                                                                                     
4578 -            if (mLabelCache.containsKey(keyB)) {                                                                  
4579 -                labelB = mLabelCache.get(keyB).toString();                                                        
4580 -            } else {                                                                                              
4581 -                labelB = b.getLabel().toString().trim();                                                          
4582 -                                                                                                                  
4583 -                mLabelCache.put(keyB, labelB);                                                                    
4584 -            }                                                                                                     
4585 -            return mCollator.compare(labelA, labelB);                                                             
4586 -        }                                                                                                         
4587 -    };                                                                                                            
4588 -    public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
4589 -        private final AppWidgetManagerCompat mManager;                                                            
4590 -        private final PackageManager mPackageManager;                                                             
4591 -        private final HashMap<Object, String> mLabelCache;                                                        
4592 -        private final Collator mCollator;                                                                         
4593 -                                                                                                                  
4594 -        WidgetAndShortcutNameComparator(Context context) {                                                        
4595 -            mManager = AppWidgetManagerCompat.getInstance(context);                                               
4596 -            mPackageManager = context.getPackageManager();                                                        
4597 -            mLabelCache = new HashMap<Object, String>();                                                          
4598 -            mCollator = Collator.getInstance();                                                                   
4599 -        }                                                                                                         
4600 -        public final int compare(Object a, Object b) {                                                            
4601 -            String labelA, labelB;                                                                                
4602 -            if (mLabelCache.containsKey(a)) {                                                                     
4603 -                labelA = mLabelCache.get(a);                                                                      
4604 -            } else {                                                                                              
4605 -                labelA = (a instanceof LauncherAppWidgetProviderInfo)                                             
4606 -                        ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                                   
4607 -                        : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                         
4608 -                mLabelCache.put(a, labelA);                                                                       
4609 -            }                                                                                                     
4610 -            if (mLabelCache.containsKey(b)) {                                                                     
4611 -                labelB = mLabelCache.get(b);                                                                      
4612 -            } else {                                                                                              
4613 -                labelB = (b instanceof LauncherAppWidgetProviderInfo)                                             
4614 -                        ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                                   
4615 -                        : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                         
4616 -                mLabelCache.put(b, labelB);                                                                       
4617 -            }                                                                                                     
4618 -            return mCollator.compare(labelA, labelB);                                                             
4619 -        }                                                                                                         
4620 -    };                                                                                                            
4621                                                                                                                    
4622      static boolean isValidProvider(AppWidgetProviderInfo provider) {                                              
4623          return (provider != null) && (provider.provider != null)                                                  
4624                  && (provider.provider.getPackageName() != null);                                                  
4625      }                                                                                                             
4626                                                                                                                    
4627      public void dumpState() {                                                                                     
4628          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
4629          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
4630          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
4631          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
4632          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
4633          if (mLoaderTask != null) {                                                                                
4634              mLoaderTask.dumpState();                                                                              
4635          } else {                                                                                                  
4636              Log.d(TAG, "mLoaderTask=null");                                                                       
4637          }                                                                                                         
4638      }                                                                                                             
4639                                                                                                                    
4640      public Callbacks getCallback() {                                                                              
4641          return mCallbacks != null ? mCallbacks.get() : null;                                                      
4642      }                                                                                                             
4643 +                                                                                                                  
4644 +    /**                                                                                                           
4645 +     * @return {@link FolderInfo} if its already loaded.                                                          
4646 +     */                                                                                                           
4647 +    public FolderInfo findFolderById(Long folderId) {                                                             
4648 +        synchronized (sBgLock) {                                                                                  
4649 +            return sBgFolders.get(folderId);                                                                      
4650 +        }                                                                                                         
4651 +    }                                                                                                             
4652 +                                                                                                                  
4653 +    /**                                                                                                           
4654 +     * @return the looper for the worker thread which can be used to start background tasks.                      
4655 +     */                                                                                                           
4656 +    public static Looper getWorkerLooper() {                                                                      
4657 +        return sWorkerThread.getLooper();                                                                         
4658 +    }                                                                                                             
4659  }                                                                                                                 
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetProviderInfo;                                                                   
  21  import android.content.BroadcastReceiver;                                                                         
  22  import android.content.ComponentName;                                                                             
  23  import android.content.ContentProviderClient;                                                                     
  24  import android.content.ContentProviderOperation;                                                                  
  25  import android.content.ContentResolver;                                                                           
  26  import android.content.ContentValues;                                                                             
  27  import android.content.Context;                                                                                   
  28  import android.content.Intent;                                                                                    
  29  import android.content.Intent.ShortcutIconResource;                                                               
  30  import android.content.IntentFilter;                                                                              
  31  import android.content.SharedPreferences;                                                                         
  32  import android.content.pm.PackageManager;                                                                         
  33  import android.content.pm.ProviderInfo;                                                                           
  34  import android.content.pm.ResolveInfo;                                                                            
  35  import android.content.res.Configuration;                                                                         
  36  import android.content.res.Resources;                                                                             
  37  import android.database.Cursor;                                                                                   
  38  import android.graphics.Bitmap;                                                                                   
  39  import android.graphics.BitmapFactory;                                                                            
  40  import android.graphics.Rect;                                                                                     
  41  import android.net.Uri;                                                                                           
  42  import android.os.Build;                                                                                          
  43  import android.os.Environment;                                                                                    
  44  import android.os.Handler;                                                                                        
  45  import android.os.HandlerThread;                                                                                  

  46  import android.os.Parcelable;                                                                                     
  47  import android.os.Process;                                                                                        
  48  import android.os.RemoteException;                                                                                
  49  import android.os.SystemClock;                                                                                    
  50  import android.os.TransactionTooLargeException;                                                                   
  51  import android.provider.BaseColumns;                                                                              
  52  import android.text.TextUtils;                                                                                    
  53  import android.util.Log;                                                                                          
  54  import android.util.LongSparseArray;                                                                              
  55  import android.util.Pair;                                                                                         
  56                                                                                                                    
  57  import com.android.launcher3.compat.AppWidgetManagerCompat;                                                       
  58  import com.android.launcher3.compat.LauncherActivityInfoCompat;                                                   
  59  import com.android.launcher3.compat.LauncherAppsCompat;                                                           
  60  import com.android.launcher3.compat.PackageInstallerCompat;                                                       
  61  import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                                    
  62  import com.android.launcher3.compat.UserHandleCompat;                                                             
  63  import com.android.launcher3.compat.UserManagerCompat;                                                            

  64  import com.android.launcher3.util.ComponentKey;                                                                   




  65                                                                                                                    
  66  import java.lang.ref.WeakReference;                                                                               
  67  import java.net.URISyntaxException;                                                                               
  68  import java.security.InvalidParameterException;                                                                   
  69  import java.text.Collator;                                                                                        
  70  import java.util.ArrayList;                                                                                       
  71  import java.util.Arrays;                                                                                          
  72  import java.util.Collection;                                                                                      
  73  import java.util.Collections;                                                                                     
  74  import java.util.Comparator;                                                                                      
  75  import java.util.HashMap;                                                                                         
  76  import java.util.HashSet;                                                                                         
  77  import java.util.Iterator;                                                                                        
  78  import java.util.List;                                                                                            
  79  import java.util.Map.Entry;                                                                                       
  80  import java.util.Set;                                                                                             
  81  import java.util.TreeMap;                                                                                         
  82                                                                                                                    
  83  /**                                                                                                               
  84   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  85   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  86   * for the Launcher.                                                                                              
  87   */                                                                                                               
  88  public class LauncherModel extends BroadcastReceiver                                                              
  89          implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                               
  90      static final boolean DEBUG_LOADERS = false;                                                                   
  91      private static final boolean DEBUG_RECEIVER = false;                                                          
  92      private static final boolean REMOVE_UNRESTORED_ICONS = true;                                                  
  93      private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                           
  94                                                                                                                    
  95      static final String TAG = "Launcher.Model";                                                                   
  96                                                                                                                    
  97      // true = use a "More Apps" folder for non-workspace apps on upgrade                                          
  98      // false = strew non-workspace apps across the workspace on upgrade                                           
  99      public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                             
 100      public static final int LOADER_FLAG_NONE = 0;                                                                 
 101      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
 102      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
 103                                                                                                                    
 104      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
 105      private static final long INVALID_SCREEN_ID = -1L;                                                            
 106                                                                                                                    
 107      private final boolean mAppsCanBeOnRemoveableStorage;                                                          

 108      private final boolean mOldContentProviderExists;                                                              
 109                                                                                                                    
 110      private final LauncherAppState mApp;                                                                          
 111      private final Object mLock = new Object();                                                                    
 112      private DeferredHandler mHandler = new DeferredHandler();                                                     
 113      private LoaderTask mLoaderTask;                                                                               
 114      private boolean mIsLoaderTaskRunning;                                                                         
 115                                                                                                                    
 116      /**                                                                                                           
 117       * Maintain a set of packages per user, for which we added a shortcut on the workspace.                       
 118       */                                                                                                           
 119      private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";             
 120                                                                                                                    
 121      // Specific runnable types that are run on the main thread deferred handler, this allows us to                
 122      // clear all queued binding runnables when the Launcher activity is destroyed.                                
 123      private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
 124      private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    






 125                                                                                                                    
 126      private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                             
 127                                                                                                                    
 128      private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      

 129      static {                                                                                                      
 130          sWorkerThread.start();                                                                                    
 131      }                                                                                                             
 132      private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                

 133                                                                                                                    
 134      // We start off with everything not loaded.  After that, we assume that                                       
 135      // our monitoring of the package manager provides all updates and we never                                    
 136      // need to do a requery.  These are only ever touched from the loader thread.                                 
 137      private boolean mWorkspaceLoaded;                                                                             
 138      private boolean mAllAppsLoaded;                                                                               


 139                                                                                                                    
 140      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 141      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 142      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 143      // a normal load, we also clear this set of Runnables.                                                        
 144      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 145                                                                                                                    
 146      private WeakReference<Callbacks> mCallbacks;                                                                  







 147                                                                                                                    
 148      // < only access in worker thread >                                                                           
 149      AllAppsList mBgAllAppsList;                                                                                   


 150                                                                                                                    
 151      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 152      // other locks, this one can generally be held long-term because we never expect any of these                 
 153      // static data structures to be referenced outside of the worker thread except on the first                   
 154      // load after configuration change.                                                                           
 155      static final Object sBgLock = new Object();                                                                   
 156                                                                                                                    
 157      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 158      // LauncherModel to their ids                                                                                 
 159      static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           

 160                                                                                                                    
 161      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 162      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 163      //       shortcuts within folders).                                                                           
 164      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 165                                                                                                                    
 166      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 167      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 168          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 169                                                                                                                    
 170      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 171      static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 172                                                                                                                    
 173      // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 174      static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          

 175                                                                                                                    
 176      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 177      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 178                                                                                                                    
 179      // sBgWidgetProviders is the set of widget providers including custom internal widgets                        
 180      public static HashMap<ComponentKey, LauncherAppWidgetProviderInfo> sBgWidgetProviders;                        
 181                                                                                                                    
 182      // sPendingPackages is a set of packages which could be on sdcard and are not available yet                   
 183      static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                                    
 184              new HashMap<UserHandleCompat, HashSet<String>>();                                                     
 185                                                                                                                    
 186      // </ only access in worker thread >                                                                          
 187                                                                                                                    
 188      private IconCache mIconCache;                                                                                 
 189                                                                                                                    
 190      protected int mPreviousConfigMcc;                                                                             
 191                                                                                                                    
 192      private final LauncherAppsCompat mLauncherApps;                                                               
 193      private final UserManagerCompat mUserManager;                                                                 




 194                                                                                                                    
 195      public interface Callbacks {                                                                                  
 196          public boolean setLoadOnResume();                                                                         
 197          public int getCurrentWorkspaceScreen();                                                                   
 198          public void startBinding();                                                                               
 199          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 200                                boolean forceAnimateIcons);                                                         
 201          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 202          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 203          public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 204          public void finishBindingItems(boolean upgradePath);                                                      


 205          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 206          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 207          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 208                                    ArrayList<ItemInfo> addNotAnimated,                                             
 209                                    ArrayList<ItemInfo> addAnimated,                                                
 210                                    ArrayList<AppInfo> addedApps);                                                  
 211          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 212          public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                         
 213                  ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                          
 214          public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                                
 215          public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                                
 216          public void updatePackageBadge(String packageName);                                                       

 217          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 218                          ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                          
 219          public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   

 220          public void bindSearchablesChanged();                                                                     
 221          public boolean isAllAppsButtonRank(int rank);                                                             
 222          public void onPageBoundSynchronously(int page);                                                           
 223          public void dumpLogsToLocalData();                                                                        
 224          public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,                    
 225                  int[] cell, int spanX, int spanY);                                                                
 226      }                                                                                                             
 227                                                                                                                    
 228      public interface ItemInfoFilter {                                                                             
 229          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 230      }                                                                                                             
 231                                                                                                                    
 232      public interface ScreenPosProvider {                                                                          
 233          int getScreenIndex(ArrayList<Long> screenIDs);                                                            
 234      }                                                                                                             
 235                                                                                                                    
 236      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 237          Context context = app.getContext();                                                                       
 238                                                                                                                    
 239          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 240          String oldProvider = context.getString(R.string.old_launcher_provider_uri);                               
 241          // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different                        
 242          // resource string.                                                                                       
 243          String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                         
 244          ProviderInfo providerInfo =                                                                               
 245                  context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                         
 246          ProviderInfo redirectProvider =                                                                           
 247                  context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                         
 248                                                                                                                    
 249          Log.d(TAG, "Old launcher provider: " + oldProvider);                                                      
 250          mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                         
 251                                                                                                                    
 252          if (mOldContentProviderExists) {                                                                          
 253              Log.d(TAG, "Old launcher provider exists.");                                                          
 254          } else {                                                                                                  
 255              Log.d(TAG, "Old launcher provider does not exist.");                                                  
 256          }                                                                                                         
 257                                                                                                                    
 258          mApp = app;                                                                                               
 259          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   

 260          mIconCache = iconCache;                                                                                   
 261                                                                                                                    
 262          final Resources res = context.getResources();                                                             
 263          Configuration config = res.getConfiguration();                                                            
 264          mPreviousConfigMcc = config.mcc;                                                                          
 265          mLauncherApps = LauncherAppsCompat.getInstance(context);                                                  
 266          mUserManager = UserManagerCompat.getInstance(context);                                                    
 267      }                                                                                                             
 268                                                                                                                    
 269      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 270       * posted on the main thread handler. */                                                                      
 271      private void runOnMainThread(Runnable r) {                                                                    
 272          runOnMainThread(r, 0);                                                                                    
 273      }                                                                                                             
 274      private void runOnMainThread(Runnable r, int type) {                                                          

 275          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 276              // If we are on the worker thread, post onto the main handler                                         
 277              mHandler.post(r);                                                                                     
 278          } else {                                                                                                  
 279              r.run();                                                                                              
 280          }                                                                                                         
 281      }                                                                                                             
 282                                                                                                                    
 283      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 284       * posted on the worker thread handler. */                                                                    
 285      private static void runOnWorkerThread(Runnable r) {                                                           
 286          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 287              r.run();                                                                                              
 288          } else {                                                                                                  
 289              // If we are not on the worker thread, then post to the worker handler                                
 290              sWorker.post(r);                                                                                      
 291          }                                                                                                         
 292      }                                                                                                             
 293                                                                                                                    













 294      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 295          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 296      }                                                                                                             
 297                                                                                                                    
 298      public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                                
 299          // Process the updated package state                                                                      
 300          Runnable r = new Runnable() {                                                                             




 301              public void run() {                                                                                   
 302                  Callbacks callbacks = getCallback();                                                              
 303                  if (callbacks != null) {                                                                          
 304                      callbacks.updatePackageState(installInfo);                                                    












































 305                  }                                                                                                 
 306              }                                                                                                     
 307          };                                                                                                        
 308          mHandler.post(r);                                                                                         
 309      }                                                                                                             
 310                                                                                                                    
 311      public void updatePackageBadge(final String packageName) {                                                    
 312          // Process the updated package badge                                                                      
 313          Runnable r = new Runnable() {                                                                             










 314              public void run() {                                                                                   
 315                  Callbacks callbacks = getCallback();                                                              
 316                  if (callbacks != null) {                                                                          
 317                      callbacks.updatePackageBadge(packageName);                                                    





































 318                  }                                                                                                 
 319              }                                                                                                     
 320          };                                                                                                        
 321          mHandler.post(r);                                                                                         

 322      }                                                                                                             
 323                                                                                                                    
 324      public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 325          final Callbacks callbacks = getCallback();                                                                
 326                                                                                                                    
 327          if (allAppsApps == null) {                                                                                
 328              throw new RuntimeException("allAppsApps must not be null");                                           
 329          }                                                                                                         
 330          if (allAppsApps.isEmpty()) {                                                                              
 331              return;                                                                                               
 332          }                                                                                                         
 333                                                                                                                    
 334          // Process the newly added applications and add them to the database first                                
 335          Runnable r = new Runnable() {                                                                             
 336              public void run() {                                                                                   
 337                  runOnMainThread(new Runnable() {                                                                  
 338                      public void run() {                                                                           
 339                          Callbacks cb = getCallback();                                                             
 340                          if (callbacks == cb && cb != null) {                                                      
 341                              callbacks.bindAppsAdded(null, null, null, allAppsApps);                               
 342                          }                                                                                         
 343                      }                                                                                             
 344                  });                                                                                               
 345              }                                                                                                     
 346          };                                                                                                        
 347          runOnWorkerThread(r);                                                                                     
 348      }                                                                                                             
 349                                                                                                                    
 350      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 351              final ArrayList<ItemInfo> workspaceApps) {                                                            
 352          addAndBindAddedWorkspaceApps(context, workspaceApps,                                                      
 353                  new ScreenPosProvider() {                                                                         
 354                                                                                                                    
 355                      @Override                                                                                     
 356                      public int getScreenIndex(ArrayList<Long> screenIDs) {                                        
 357                          return screenIDs.isEmpty() ? 0 : 1;                                                       
 358                      }                                                                                             
 359                  }, 1, false);                                                                                     
 360      }                                                                                                             
 361                                                                                                                    
 362      private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,                        

 363              int[] xy, int spanX, int spanY) {                                                                     
 364          LauncherAppState app = LauncherAppState.getInstance();                                                    
 365          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 366          final int xCount = (int) grid.numColumns;                                                                 
 367          final int yCount = (int) grid.numRows;                                                                    



 368          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 369          if (occupiedPos != null) {                                                                                
 370              for (Rect r : occupiedPos) {                                                                          
 371                  for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                                  
 372                      for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                              





 373                          occupied[x][y] = true;                                                                    
 374                      }                                                                                             
 375                  }                                                                                                 
 376              }                                                                                                     
 377          }                                                                                                         
 378          return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                             

 379      }                                                                                                             
 380                                                                                                                    
 381      /**                                                                                                           
 382       * Find a position on the screen for the given size or adds a new screen.                                     
 383       * @return screenId and the coordinates for the item.                                                         
 384       */                                                                                                           
 385      private static Pair<Long, int[]> findSpaceForItem(                                                            

 386              Context context,                                                                                      
 387              ScreenPosProvider preferredScreen,                                                                    
 388              int fallbackStartScreen,                                                                              
 389              ArrayList<Long> workspaceScreens,                                                                     
 390              ArrayList<Long> addedWorkspaceScreensFinal,                                                           
 391              int spanX, int spanY) {                                                                               
 392          // Load position of items which are on the desktop. We can't use sBgItemsIdMap because                    
 393          // loadWorkspace() may not have been called.                                                              
 394          final ContentResolver cr = context.getContentResolver();                                                  
 395          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 396                  new String[] {                                                                                    
 397                      LauncherSettings.Favorites.SCREEN,                                                            
 398                      LauncherSettings.Favorites.CELLX,                                                             
 399                      LauncherSettings.Favorites.CELLY,                                                             
 400                      LauncherSettings.Favorites.SPANX,                                                             
 401                      LauncherSettings.Favorites.SPANY,                                                             
 402                      LauncherSettings.Favorites.CONTAINER                                                          
 403                   },                                                                                               
 404                   "container=?",                                                                                   
 405                   new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },                 
 406                   null);                                                                                           
 407                                                                                                                    
 408          final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 409          final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 410          final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 411          final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 412          final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 413          LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();                    
 414          try {                                                                                                     
 415              while (c.moveToNext()) {                                                                              
 416                  Rect rect = new Rect();                                                                           
 417                  rect.left = c.getInt(cellXIndex);                                                                 
 418                  rect.top = c.getInt(cellYIndex);                                                                  
 419                  rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                                       
 420                  rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                                       
 421                                                                                                                    
 422                  long screenId = c.getInt(screenIndex);                                                            
 423                  ArrayList<Rect> items = screenItems.get(screenId);                                                
 424                  if (items == null) {                                                                              
 425                      items = new ArrayList<Rect>();                                                                
 426                      screenItems.put(screenId, items);                                                             
 427                  }                                                                                                 
 428                  items.add(rect);                                                                                  
 429              }                                                                                                     
 430          } catch (Exception e) {                                                                                   
 431              screenItems.clear();                                                                                  
 432          } finally {                                                                                               
 433              c.close();                                                                                            















 434          }                                                                                                         
 435                                                                                                                    
 436          // Find appropriate space for the item.                                                                   
 437          long screenId = 0;                                                                                        
 438          int[] cordinates = new int[2];                                                                            
 439          boolean found = false;                                                                                    
 440                                                                                                                    
 441          int screenCount = workspaceScreens.size();                                                                
 442          // First check the preferred screen.                                                                      
 443          int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                              

 444          if (preferredScreenIndex < screenCount) {                                                                 
 445              screenId = workspaceScreens.get(preferredScreenIndex);                                                
 446              found = findNextAvailableIconSpaceInScreen(                                                           
 447                      screenItems.get(screenId), cordinates, spanX, spanY);                                         
 448          }                                                                                                         
 449                                                                                                                    
 450          if (!found) {                                                                                             
 451              // Search on any of the screens.                                                                      
 452              for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                              


 453                  screenId = workspaceScreens.get(screen);                                                          
 454                  if (findNextAvailableIconSpaceInScreen(                                                           
 455                          screenItems.get(screenId), cordinates, spanX, spanY)) {                                   
 456                      // We found a space for it                                                                    
 457                      found = true;                                                                                 
 458                      break;                                                                                        
 459                  }                                                                                                 
 460              }                                                                                                     
 461          }                                                                                                         
 462                                                                                                                    
 463          if (!found) {                                                                                             
 464              // Still no position found. Add a new screen to the end.                                              
 465              screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                              
 466                                                                                                                    
 467              // Save the screen id for binding in the workspace                                                    
 468              workspaceScreens.add(screenId);                                                                       
 469              addedWorkspaceScreensFinal.add(screenId);                                                             
 470                                                                                                                    
 471              // If we still can't find an empty space, then God help us all!!!                                     
 472              if (!findNextAvailableIconSpaceInScreen(                                                              
 473                      screenItems.get(screenId), cordinates, spanX, spanY)) {                                       
 474                  throw new RuntimeException("Can't find space to add the item");                                   
 475              }                                                                                                     
 476          }                                                                                                         
 477          return Pair.create(screenId, cordinates);                                                                 
 478      }                                                                                                             
 479                                                                                                                    
 480      /**                                                                                                           
 481       * Adds the provided items to the workspace.                                                                  
 482       * @param preferredScreen the screen where we should try to add the app first                                 
 483       * @param fallbackStartScreen the screen to start search for empty space if                                   
 484       * preferredScreen is not available.                                                                          
 485       */                                                                                                           
 486      public void addAndBindPendingItem(                                                                            
 487              final Context context,                                                                                
 488              final PendingAddItemInfo addInfo,                                                                     
 489              final ScreenPosProvider preferredScreen,                                                              
 490              final int fallbackStartScreen) {                                                                      
 491          final Callbacks callbacks = getCallback();                                                                
 492          // Process the newly added applications and add them to the database first                                
 493          Runnable r = new Runnable() {                                                                             
 494              public void run() {                                                                                   
 495                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 496                                                                                                                    
 497                  ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 498                  TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 499                  for (Integer i : orderedScreens.keySet()) {                                                       
 500                      long screenId = orderedScreens.get(i);                                                        
 501                      workspaceScreens.add(screenId);                                                               
 502                  }                                                                                                 
 503                                                                                                                    
 504                  // Find appropriate space for the item.                                                           
 505                  Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                             
 506                          fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                        
 507                          addInfo.spanX,                                                                            
 508                          addInfo.spanY);                                                                           
 509                  final long screenId = coords.first;                                                               
 510                  final int[] cordinates = coords.second;                                                           
 511                                                                                                                    
 512                  // Update the workspace screens                                                                   
 513                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 514                  runOnMainThread(new Runnable() {                                                                  
 515                      public void run() {                                                                           
 516                          Callbacks cb = getCallback();                                                             
 517                          if (callbacks == cb && cb != null) {                                                      
 518                              cb.bindAddScreens(addedWorkspaceScreensFinal);                                        
 519                              cb.bindAddPendingItem(addInfo,                                                        
 520                                      LauncherSettings.Favorites.CONTAINER_DESKTOP,                                 
 521                                      screenId, cordinates, addInfo.spanX, addInfo.spanY);                          
 522                          }                                                                                         
 523                      }                                                                                             
 524                  });                                                                                               
 525              }                                                                                                     
 526          };                                                                                                        
 527          runOnWorkerThread(r);                                                                                     
 528      }                                                                                                             
 529                                                                                                                    
 530      /**                                                                                                           
 531       * Adds the provided items to the workspace.                                                                  
 532       * @param preferredScreen the screen where we should try to add the app first                                 
 533       * @param fallbackStartScreen the screen to start search for empty space if                                   
 534       * preferredScreen is not available.                                                                          
 535       */                                                                                                           
 536      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 537              final ArrayList<ItemInfo> workspaceApps,                                                              
 538              final ScreenPosProvider preferredScreen,                                                              
 539              final int fallbackStartScreen,                                                                        
 540              final boolean allowDuplicate) {                                                                       


 541          final Callbacks callbacks = getCallback();                                                                
 542          if (workspaceApps.isEmpty()) {                                                                            
 543              return;                                                                                               
 544          }                                                                                                         
 545          // Process the newly added applications and add them to the database first                                
 546          Runnable r = new Runnable() {                                                                             
 547              public void run() {                                                                                   
 548                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 549                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 550                                                                                                                    
 551                  // Get the list of workspace screens.  We need to append to this list and                         
 552                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 553                  // called.                                                                                        
 554                  ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 555                  TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 556                  for (Integer i : orderedScreens.keySet()) {                                                       
 557                      long screenId = orderedScreens.get(i);                                                        
 558                      workspaceScreens.add(screenId);                                                               
 559                  }                                                                                                 
 560                                                                                                                    

 561                  synchronized(sBgLock) {                                                                           
 562                      for (ItemInfo item : workspaceApps) {                                                         
 563                          if (!allowDuplicate) {                                                                    

 564                              // Short-circuit this logic if the icon exists somewhere on the workspace             
 565                              if (shortcutExists(context, item.title.toString(),                                    
 566                                      item.getIntent(), item.user)) {                                               

 567                                  continue;                                                                         
 568                              }                                                                                     
 569                          }                                                                                         
 570                                                                                                                    
 571                          // Find appropriate space for the item.                                                   
 572                          Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                     
 573                                  fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                


 574                                  1, 1);                                                                            
 575                          long screenId = coords.first;                                                             
 576                          int[] cordinates = coords.second;                                                         
 577                                                                                                                    
 578                          ShortcutInfo shortcutInfo;                                                                
 579                          if (item instanceof ShortcutInfo) {                                                       
 580                              shortcutInfo = (ShortcutInfo) item;                                                   



 581                          } else if (item instanceof AppInfo) {                                                     
 582                              shortcutInfo = ((AppInfo) item).makeShortcut();                                       

 583                          } else {                                                                                  
 584                              throw new RuntimeException("Unexpected info type");                                   
 585                          }                                                                                         
 586                                                                                                                    
 587                          // Add the shortcut to the db                                                             
 588                          addItemToDatabase(context, shortcutInfo,                                                  

 589                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 590                                  screenId, cordinates[0], cordinates[1], false);                                   

 591                          // Save the ShortcutInfo for binding in the workspace                                     
 592                          addedShortcutsFinal.add(shortcutInfo);                                                    

 593                      }                                                                                             
 594                  }                                                                                                 
 595                                                                                                                    
 596                  // Update the workspace screens                                                                   
 597                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 598                                                                                                                    
 599                  if (!addedShortcutsFinal.isEmpty()) {                                                             
 600                      runOnMainThread(new Runnable() {                                                              
 601                          public void run() {                                                                       
 602                              Callbacks cb = getCallback();                                                         
 603                              if (callbacks == cb && cb != null) {                                                  
 604                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 605                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 606                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 607                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 608                                      long lastScreenId = info.screenId;                                            
 609                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 610                                          if (i.screenId == lastScreenId) {                                         
 611                                              addAnimated.add(i);                                                   
 612                                          } else {                                                                  
 613                                              addNotAnimated.add(i);                                                
 614                                          }                                                                         
 615                                      }                                                                             
 616                                  }                                                                                 
 617                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 618                                          addNotAnimated, addAnimated, null);                                       
 619                              }                                                                                     
 620                          }                                                                                         
 621                      });                                                                                           
 622                  }                                                                                                 
 623              }                                                                                                     
 624          };                                                                                                        
 625          runOnWorkerThread(r);                                                                                     
 626      }                                                                                                             
 627                                                                                                                    
 628      public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    

 629          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 630              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 631                      "main thread");                                                                               
 632          }                                                                                                         
 633                                                                                                                    
 634          // Clear any deferred bind runnables                                                                      
 635          synchronized (mDeferredBindRunnables) {                                                                   
 636              mDeferredBindRunnables.clear();                                                                       
 637          }                                                                                                         
 638          // Remove any queued bind runnables                                                                       
 639          mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          



 640          // Unbind all the workspace items                                                                         
 641          unbindWorkspaceItemsOnMainThread();                                                                       
 642      }                                                                                                             
 643                                                                                                                    
 644      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 645      void unbindWorkspaceItemsOnMainThread() {                                                                     
 646          // Ensure that we don't use the same workspace items data structure on the main thread                    
 647          // by making a copy of workspace items first.                                                             
 648          final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 649          final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      

 650          synchronized (sBgLock) {                                                                                  
 651              tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 652              tmpAppWidgets.addAll(sBgAppWidgets);                                                                  


 653          }                                                                                                         
 654          Runnable r = new Runnable() {                                                                             
 655                  @Override                                                                                         
 656                  public void run() {                                                                               
 657                     for (ItemInfo item : tmpWorkspaceItems) {                                                      
 658                         item.unbind();                                                                             
 659                     }                                                                                              
 660                     for (ItemInfo item : tmpAppWidgets) {                                                          

 661                         item.unbind();                                                                             
 662                     }                                                                                              
 663                  }                                                                                                 
 664              };                                                                                                    
 665          runOnMainThread(r);                                                                                       
 666      }                                                                                                             
 667                                                                                                                    
 668      /**                                                                                                           
 669       * Adds an item to the DB if it was not created previously, or move it to a new                               
 670       * <container, screen, cellX, cellY>                                                                          
 671       */                                                                                                           
 672      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 673              long screenId, int cellX, int cellY) {                                                                
 674          if (item.container == ItemInfo.NO_ID) {                                                                   
 675              // From all apps                                                                                      
 676              addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           

 677          } else {                                                                                                  
 678              // From somewhere else                                                                                
 679              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 680          }                                                                                                         
 681      }                                                                                                             
 682                                                                                                                    
 683      static void checkItemInfoLocked(                                                                              
 684              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 685          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 686          if (modelItem != null && item != modelItem) {                                                             
 687              // check all the data is consistent                                                                   
 688              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 689                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 690                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 691                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 692                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 693                          modelShortcut.id == shortcut.id &&                                                        
 694                          modelShortcut.itemType == shortcut.itemType &&                                            
 695                          modelShortcut.container == shortcut.container &&                                          
 696                          modelShortcut.screenId == shortcut.screenId &&                                            
 697                          modelShortcut.cellX == shortcut.cellX &&                                                  
 698                          modelShortcut.cellY == shortcut.cellY &&                                                  
 699                          modelShortcut.spanX == shortcut.spanX &&                                                  
 700                          modelShortcut.spanY == shortcut.spanY &&                                                  
 701                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 702                          (modelShortcut.dropPos != null &&                                                         
 703                                  shortcut.dropPos != null &&                                                       
 704                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 705                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 706                      // For all intents and purposes, this is the same object                                      
 707                      return;                                                                                       
 708                  }                                                                                                 
 709              }                                                                                                     
 710                                                                                                                    
 711              // the modelItem needs to match up perfectly with item if our model is                                
 712              // to be consistent with the database-- for now, just require                                         
 713              // modelItem == item or the equality check above                                                      
 714              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 715                      "modelItem: " +                                                                               
 716                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 717                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 718              RuntimeException e = new RuntimeException(msg);                                                       
 719              if (stackTrace != null) {                                                                             
 720                  e.setStackTrace(stackTrace);                                                                      
 721              }                                                                                                     
 722              throw e;                                                                                              
 723          }                                                                                                         
 724      }                                                                                                             
 725                                                                                                                    
 726      static void checkItemInfo(final ItemInfo item) {                                                              
 727          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 728          final long itemId = item.id;                                                                              
 729          Runnable r = new Runnable() {                                                                             
 730              public void run() {                                                                                   
 731                  synchronized (sBgLock) {                                                                          
 732                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 733                  }                                                                                                 
 734              }                                                                                                     
 735          };                                                                                                        
 736          runOnWorkerThread(r);                                                                                     
 737      }                                                                                                             
 738                                                                                                                    
 739      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 740              final ItemInfo item, final String callingFunction) {                                                  
 741          final long itemId = item.id;                                                                              
 742          final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  

 743          final ContentResolver cr = context.getContentResolver();                                                  
 744                                                                                                                    
 745          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 746          Runnable r = new Runnable() {                                                                             
 747              public void run() {                                                                                   
 748                  cr.update(uri, values, null, null);                                                               
 749                  updateItemArrays(item, itemId, stackTrace);                                                       
 750              }                                                                                                     
 751          };                                                                                                        
 752          runOnWorkerThread(r);                                                                                     
 753      }                                                                                                             
 754                                                                                                                    
 755      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 756              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 757          final ContentResolver cr = context.getContentResolver();                                                  
 758                                                                                                                    
 759          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 760          Runnable r = new Runnable() {                                                                             
 761              public void run() {                                                                                   
 762                  ArrayList<ContentProviderOperation> ops =                                                         
 763                          new ArrayList<ContentProviderOperation>();                                                
 764                  int count = items.size();                                                                         
 765                  for (int i = 0; i < count; i++) {                                                                 
 766                      ItemInfo item = items.get(i);                                                                 
 767                      final long itemId = item.id;                                                                  
 768                      final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      

 769                      ContentValues values = valuesList.get(i);                                                     
 770                                                                                                                    
 771                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 772                      updateItemArrays(item, itemId, stackTrace);                                                   
 773                                                                                                                    
 774                  }                                                                                                 
 775                  try {                                                                                             
 776                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 777                  } catch (Exception e) {                                                                           
 778                      e.printStackTrace();                                                                          
 779                  }                                                                                                 
 780              }                                                                                                     
 781          };                                                                                                        
 782          runOnWorkerThread(r);                                                                                     
 783      }                                                                                                             
 784                                                                                                                    
 785      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 786          // Lock on mBgLock *after* the db operation                                                               
 787          synchronized (sBgLock) {                                                                                  
 788              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 789                                                                                                                    
 790              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 791                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 792                  // Item is in a folder, make sure this folder exists                                              
 793                  if (!sBgFolders.containsKey(item.container)) {                                                    
 794                      // An items container is being set to a that of an item which is not in                       
 795                      // the list of Folders.                                                                       
 796                      String msg = "item: " + item + " container being set to: " +                                  
 797                              item.container + ", not in the list of folders";                                      
 798                      Log.e(TAG, msg);                                                                              
 799                  }                                                                                                 
 800              }                                                                                                     
 801                                                                                                                    
 802              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
 803              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
 804              // that are on the desktop, as appropriate                                                            
 805              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
 806              if (modelItem != null &&                                                                              
 807                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
 808                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
 809                  switch (modelItem.itemType) {                                                                     
 810                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
 811                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
 812                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 813                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
 814                              sBgWorkspaceItems.add(modelItem);                                                     
 815                          }                                                                                         
 816                          break;                                                                                    
 817                      default:                                                                                      
 818                          break;                                                                                    
 819                  }                                                                                                 
 820              } else {                                                                                              
 821                  sBgWorkspaceItems.remove(modelItem);                                                              
 822              }                                                                                                     
 823          }                                                                                                         
 824      }                                                                                                             
 825                                                                                                                    
 826      /**                                                                                                           
 827       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
 828       */                                                                                                           
 829      static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    

 830              final long screenId, final int cellX, final int cellY) {                                              
 831          item.container = container;                                                                               
 832          item.cellX = cellX;                                                                                       
 833          item.cellY = cellY;                                                                                       
 834                                                                                                                    
 835          // We store hotseat items in canonical form which is this orientation invariant position                  
 836          // in the hotseat                                                                                         
 837          if (context instanceof Launcher && screenId < 0 &&                                                        
 838                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 839              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 840          } else {                                                                                                  
 841              item.screenId = screenId;                                                                             
 842          }                                                                                                         
 843                                                                                                                    
 844          final ContentValues values = new ContentValues();                                                         
 845          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 846          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 847          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 848          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 849          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 850                                                                                                                    
 851          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
 852      }                                                                                                             
 853                                                                                                                    
 854      /**                                                                                                           
 855       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
 856       * cellX, cellY have already been updated on the ItemInfos.                                                   
 857       */                                                                                                           
 858      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
 859              final long container, final int screen) {                                                             
 860                                                                                                                    
 861          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
 862          int count = items.size();                                                                                 
 863                                                                                                                    
 864          for (int i = 0; i < count; i++) {                                                                         
 865              ItemInfo item = items.get(i);                                                                         
 866              item.container = container;                                                                           
 867                                                                                                                    
 868              // We store hotseat items in canonical form which is this orientation invariant position              
 869              // in the hotseat                                                                                     
 870              if (context instanceof Launcher && screen < 0 &&                                                      
 871                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
 872                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
 873                          item.cellY);                                                                              
 874              } else {                                                                                              
 875                  item.screenId = screen;                                                                           
 876              }                                                                                                     
 877                                                                                                                    
 878              final ContentValues values = new ContentValues();                                                     
 879              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
 880              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
 881              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
 882              values.put(LauncherSettings.Favorites.RANK, item.rank);                                               
 883              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
 884                                                                                                                    
 885              contentValues.add(values);                                                                            
 886          }                                                                                                         
 887          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
 888      }                                                                                                             
 889                                                                                                                    
 890      /**                                                                                                           
 891       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
 892       */                                                                                                           
 893      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
 894              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
 895          item.container = container;                                                                               
 896          item.cellX = cellX;                                                                                       
 897          item.cellY = cellY;                                                                                       
 898          item.spanX = spanX;                                                                                       
 899          item.spanY = spanY;                                                                                       
 900                                                                                                                    
 901          // We store hotseat items in canonical form which is this orientation invariant position                  
 902          // in the hotseat                                                                                         
 903          if (context instanceof Launcher && screenId < 0 &&                                                        
 904                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 905              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 906          } else {                                                                                                  
 907              item.screenId = screenId;                                                                             
 908          }                                                                                                         
 909                                                                                                                    
 910          final ContentValues values = new ContentValues();                                                         
 911          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 912          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 913          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 914          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 915          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
 916          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
 917          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 918                                                                                                                    
 919          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
 920      }                                                                                                             
 921                                                                                                                    
 922      /**                                                                                                           
 923       * Update an item to the database in a specified container.                                                   
 924       */                                                                                                           
 925      static void updateItemInDatabase(Context context, final ItemInfo item) {                                      

 926          final ContentValues values = new ContentValues();                                                         
 927          item.onAddToDatabase(context, values);                                                                    
 928          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
 929      }                                                                                                             
 930                                                                                                                    






 931      /**                                                                                                           
 932       * Returns true if the shortcuts already exists in the database.                                              
 933       * we identify a shortcut by its title and intent.                                                            


 934       */                                                                                                           
 935      static boolean shortcutExists(Context context, String title, Intent intent,                                   
 936              UserHandleCompat user) {                                                                              
 937          final ContentResolver cr = context.getContentResolver();                                                  
 938          final Intent intentWithPkg, intentWithoutPkg;                                                             
 939                                                                                                                    



 940          if (intent.getComponent() != null) {                                                                      
 941              // If component is not null, an intent with null package will produce                                 
 942              // the same result and should also be a match.                                                        

 943              if (intent.getPackage() != null) {                                                                    
 944                  intentWithPkg = intent;                                                                           
 945                  intentWithoutPkg = new Intent(intent).setPackage(null);                                           


 946              } else {                                                                                              
 947                  intentWithPkg = new Intent(intent).setPackage(                                                    
 948                          intent.getComponent().getPackageName());                                                  
 949                  intentWithoutPkg = intent;                                                                        


 950              }                                                                                                     
 951          } else {                                                                                                  
 952              intentWithPkg = intent;                                                                               
 953              intentWithoutPkg = intent;                                                                            
 954          }                                                                                                         
 955          String userSerial = Long.toString(UserManagerCompat.getInstance(context)                                  
 956                  .getSerialNumberForUser(user));                                                                   
 957          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 958              new String[] { "title", "intent", "profileId" },                                                      
 959              "title=? and (intent=? or intent=?) and profileId=?",                                                 
 960              new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },                
 961              null);                                                                                                
 962          try {                                                                                                     
 963              return c.moveToFirst();                                                                               
 964          } finally {                                                                                               
 965              c.close();                                                                                            
 966          }                                                                                                         




















 967      }                                                                                                             
 968                                                                                                                    
 969      /**                                                                                                           
 970       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
 971       */                                                                                                           
 972      FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     

 973          final ContentResolver cr = context.getContentResolver();                                                  
 974          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
 975                  "_id=? and (itemType=? or itemType=?)",                                                           
 976                  new String[] { String.valueOf(id),                                                                
 977                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
 978                                                                                                                    
 979          try {                                                                                                     
 980              if (c.moveToFirst()) {                                                                                
 981                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
 982                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
 983                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
 984                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
 985                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
 986                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 

 987                                                                                                                    
 988                  FolderInfo folderInfo = null;                                                                     
 989                  switch (c.getInt(itemTypeIndex)) {                                                                
 990                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 991                          folderInfo = findOrMakeFolder(folderList, id);                                            
 992                          break;                                                                                    
 993                  }                                                                                                 
 994                                                                                                                    

 995                  folderInfo.title = c.getString(titleIndex);                                                       
 996                  folderInfo.id = id;                                                                               
 997                  folderInfo.container = c.getInt(containerIndex);                                                  
 998                  folderInfo.screenId = c.getInt(screenIndex);                                                      
 999                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
1000                  folderInfo.cellY = c.getInt(cellYIndex);                                                          

1001                                                                                                                    
1002                  return folderInfo;                                                                                
1003              }                                                                                                     
1004          } finally {                                                                                               
1005              c.close();                                                                                            
1006          }                                                                                                         
1007                                                                                                                    
1008          return null;                                                                                              
1009      }                                                                                                             
1010                                                                                                                    
1011      /**                                                                                                           
1012       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
1013       * cellY fields of the item. Also assigns an ID to the item.                                                  
1014       */                                                                                                           
1015      static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
1016              final long screenId, final int cellX, final int cellY, final boolean notify) {                        


1017          item.container = container;                                                                               
1018          item.cellX = cellX;                                                                                       
1019          item.cellY = cellY;                                                                                       
1020          // We store hotseat items in canonical form which is this orientation invariant position                  
1021          // in the hotseat                                                                                         
1022          if (context instanceof Launcher && screenId < 0 &&                                                        
1023                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1024              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1025          } else {                                                                                                  
1026              item.screenId = screenId;                                                                             
1027          }                                                                                                         
1028                                                                                                                    
1029          final ContentValues values = new ContentValues();                                                         
1030          final ContentResolver cr = context.getContentResolver();                                                  
1031          item.onAddToDatabase(context, values);                                                                    
1032                                                                                                                    
1033          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
1034          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
1035                                                                                                                    
1036          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
1037          Runnable r = new Runnable() {                                                                             
1038              public void run() {                                                                                   
1039                  cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
1040                          LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          

1041                                                                                                                    
1042                  // Lock on mBgLock *after* the db operation                                                       
1043                  synchronized (sBgLock) {                                                                          
1044                      checkItemInfoLocked(item.id, item, stackTrace);                                               
1045                      sBgItemsIdMap.put(item.id, item);                                                             
1046                      switch (item.itemType) {                                                                      
1047                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
1048                              sBgFolders.put(item.id, (FolderInfo) item);                                           
1049                              // Fall through                                                                       
1050                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
1051                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
1052                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
1053                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
1054                                  sBgWorkspaceItems.add(item);                                                      
1055                              } else {                                                                              
1056                                  if (!sBgFolders.containsKey(item.container)) {                                    
1057                                      // Adding an item to a folder that doesn't exist.                             
1058                                      String msg = "adding item: " + item + " to a folder that " +                  
1059                                              " doesn't exist";                                                     
1060                                      Log.e(TAG, msg);                                                              
1061                                  }                                                                                 
1062                              }                                                                                     
1063                              break;                                                                                
1064                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
1065                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
1066                              break;                                                                                
1067                      }                                                                                             
1068                  }                                                                                                 
1069              }                                                                                                     
1070          };                                                                                                        
1071          runOnWorkerThread(r);                                                                                     
1072      }                                                                                                             
1073                                                                                                                    
1074      /**                                                                                                           
1075       * Creates a new unique child id, for a given cell span across all layouts.                                   
1076       */                                                                                                           
1077      static int getCellLayoutChildId(                                                                              
1078              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
1079          return (((int) container & 0xFF) << 24)                                                                   
1080                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
1081      }                                                                                                             
1082                                                                                                                    
1083      private static ArrayList<ItemInfo> getItemsByPackageName(                                                     
1084              final String pn, final UserHandleCompat user) {                                                       
1085          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
1086              @Override                                                                                             
1087              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
1088                  return cn.getPackageName().equals(pn) && info.user.equals(user);                                  
1089              }                                                                                                     
1090          };                                                                                                        
1091          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   

1092      }                                                                                                             
1093                                                                                                                    
1094      /**                                                                                                           
1095       * Removes all the items from the database corresponding to the specified package.                            
1096       */                                                                                                           
1097      static void deletePackageFromDatabase(Context context, final String pn,                                       
1098              final UserHandleCompat user) {                                                                        
1099          deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                                        
1100      }                                                                                                             
1101                                                                                                                    
1102      /**                                                                                                           
1103       * Removes the specified item from the database                                                               
1104       * @param context                                                                                             
1105       * @param item                                                                                                
1106       */                                                                                                           
1107      static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    

1108          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
1109          items.add(item);                                                                                          
1110          deleteItemsFromDatabase(context, items);                                                                  
1111      }                                                                                                             
1112                                                                                                                    
1113      /**                                                                                                           
1114       * Removes the specified items from the database                                                              
1115       * @param context                                                                                             
1116       * @param item                                                                                                
1117       */                                                                                                           
1118      static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {             
1119          final ContentResolver cr = context.getContentResolver();                                                  
1120                                                                                                                    
1121          Runnable r = new Runnable() {                                                                             
1122              public void run() {                                                                                   
1123                  for (ItemInfo item : items) {                                                                     
1124                      final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);                     

1125                      cr.delete(uri, null, null);                                                                   
1126                                                                                                                    
1127                      // Lock on mBgLock *after* the db operation                                                   
1128                      synchronized (sBgLock) {                                                                      
1129                          switch (item.itemType) {                                                                  
1130                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1131                                  sBgFolders.remove(item.id);                                                       
1132                                  for (ItemInfo info: sBgItemsIdMap.values()) {                                     

1133                                      if (info.container == item.id) {                                              
1134                                          // We are deleting a folder which still contains items that               
1135                                          // think they are contained by that folder.                               
1136                                          String msg = "deleting a folder (" + item + ") which still " +            
1137                                                  "contains items (" + info + ")";                                  
1138                                          Log.e(TAG, msg);                                                          
1139                                      }                                                                             
1140                                  }                                                                                 
1141                                  sBgWorkspaceItems.remove(item);                                                   
1142                                  break;                                                                            
1143                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1144                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1145                                  sBgWorkspaceItems.remove(item);                                                   
1146                                  break;                                                                            
1147                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1148                                  sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                               
1149                                  break;                                                                            
1150                          }                                                                                         
1151                          sBgItemsIdMap.remove(item.id);                                                            
1152                          sBgDbIconCache.remove(item);                                                              
1153                      }                                                                                             
1154                  }                                                                                                 
1155              }                                                                                                     
1156          };                                                                                                        
1157          runOnWorkerThread(r);                                                                                     
1158      }                                                                                                             
1159                                                                                                                    
1160      /**                                                                                                           
1161       * Update the order of the workspace screens in the database. The array list contains                         
1162       * a list of screen ids in the order that they should appear.                                                 
1163       */                                                                                                           
1164      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1165          // Log to disk                                                                                            
1166          Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1167          Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1168                                                                                                                    
1169          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1170          final ContentResolver cr = context.getContentResolver();                                                  
1171          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1172                                                                                                                    
1173          // Remove any negative screen ids -- these aren't persisted                                               
1174          Iterator<Long> iter = screensCopy.iterator();                                                             
1175          while (iter.hasNext()) {                                                                                  
1176              long id = iter.next();                                                                                
1177              if (id < 0) {                                                                                         
1178                  iter.remove();                                                                                    
1179              }                                                                                                     
1180          }                                                                                                         
1181                                                                                                                    
1182          Runnable r = new Runnable() {                                                                             
1183              @Override                                                                                             
1184              public void run() {                                                                                   
1185                  ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();              
1186                  // Clear the table                                                                                
1187                  ops.add(ContentProviderOperation.newDelete(uri).build());                                         
1188                  int count = screensCopy.size();                                                                   
1189                  for (int i = 0; i < count; i++) {                                                                 
1190                      ContentValues v = new ContentValues();                                                        
1191                      long screenId = screensCopy.get(i);                                                           
1192                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1193                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1194                      ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());                       
1195                  }                                                                                                 
1196                                                                                                                    
1197                  try {                                                                                             
1198                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
1199                  } catch (Exception ex) {                                                                          
1200                      throw new RuntimeException(ex);                                                               
1201                  }                                                                                                 
1202                                                                                                                    
1203                  synchronized (sBgLock) {                                                                          
1204                      sBgWorkspaceScreens.clear();                                                                  
1205                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1206                  }                                                                                                 
1207              }                                                                                                     
1208          };                                                                                                        
1209          runOnWorkerThread(r);                                                                                     
1210      }                                                                                                             
1211                                                                                                                    
1212      /**                                                                                                           
1213       * Remove the contents of the specified folder from the database                                              
1214       */                                                                                                           
1215      static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        

1216          final ContentResolver cr = context.getContentResolver();                                                  
1217                                                                                                                    
1218          Runnable r = new Runnable() {                                                                             
1219              public void run() {                                                                                   
1220                  cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  

1221                  // Lock on mBgLock *after* the db operation                                                       
1222                  synchronized (sBgLock) {                                                                          
1223                      sBgItemsIdMap.remove(info.id);                                                                
1224                      sBgFolders.remove(info.id);                                                                   
1225                      sBgDbIconCache.remove(info);                                                                  
1226                      sBgWorkspaceItems.remove(info);                                                               
1227                  }                                                                                                 
1228                                                                                                                    
1229                  cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 

1230                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1231                  // Lock on mBgLock *after* the db operation                                                       
1232                  synchronized (sBgLock) {                                                                          
1233                      for (ItemInfo childInfo : info.contents) {                                                    
1234                          sBgItemsIdMap.remove(childInfo.id);                                                       
1235                          sBgDbIconCache.remove(childInfo);                                                         
1236                      }                                                                                             
1237                  }                                                                                                 
1238              }                                                                                                     
1239          };                                                                                                        
1240          runOnWorkerThread(r);                                                                                     
1241      }                                                                                                             
1242                                                                                                                    
1243      /**                                                                                                           
1244       * Set this as the current Launcher activity object for the loader.                                           
1245       */                                                                                                           
1246      public void initialize(Callbacks callbacks) {                                                                 
1247          synchronized (mLock) {                                                                                    



1248              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1249          }                                                                                                         
1250      }                                                                                                             
1251                                                                                                                    
1252      @Override                                                                                                     
1253      public void onPackageChanged(String packageName, UserHandleCompat user) {                                     
1254          int op = PackageUpdatedTask.OP_UPDATE;                                                                    
1255          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1256                  user));                                                                                           
1257      }                                                                                                             
1258                                                                                                                    
1259      @Override                                                                                                     
1260      public void onPackageRemoved(String packageName, UserHandleCompat user) {                                     
1261          int op = PackageUpdatedTask.OP_REMOVE;                                                                    
1262          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1263                  user));                                                                                           
1264      }                                                                                                             
1265                                                                                                                    
1266      @Override                                                                                                     
1267      public void onPackageAdded(String packageName, UserHandleCompat user) {                                       
1268          int op = PackageUpdatedTask.OP_ADD;                                                                       
1269          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1270                  user));                                                                                           
1271      }                                                                                                             
1272                                                                                                                    
1273      @Override                                                                                                     
1274      public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                                 
1275              boolean replacing) {                                                                                  
1276          if (!replacing) {                                                                                         
1277              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,                 
1278                      user));                                                                                       
1279              if (mAppsCanBeOnRemoveableStorage) {                                                                  
1280                  // Only rebind if we support removable storage. It catches the                                    
1281                  // case where                                                                                     
1282                  // apps on the external sd card need to be reloaded                                               
1283                  startLoaderFromBackground();                                                                      
1284              }                                                                                                     
1285          } else {                                                                                                  
1286              // If we are replacing then just update the packages in the list                                      
1287              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                            
1288                      packageNames, user));                                                                         
1289          }                                                                                                         
1290      }                                                                                                             
1291                                                                                                                    
1292      @Override                                                                                                     
1293      public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                               
1294              boolean replacing) {                                                                                  
1295          if (!replacing) {                                                                                         
1296              enqueuePackageUpdated(new PackageUpdatedTask(                                                         
1297                      PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                              
1298                      user));                                                                                       
1299          }                                                                                                         
1300      }                                                                                                             
1301                                                                                                                    
1302      /**                                                                                                           
1303       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1304       * ACTION_PACKAGE_CHANGED.                                                                                    
1305       */                                                                                                           
1306      @Override                                                                                                     
1307      public void onReceive(Context context, Intent intent) {                                                       
1308          if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                             
1309                                                                                                                    
1310          final String action = intent.getAction();                                                                 
1311          if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                        
1312              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1313              forceReload();                                                                                        
1314          } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1315               // Check if configuration change was an mcc/mnc change which would affect app resources              
1316               // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1317               // above for ACTION_LOCALE_CHANGED                                                                   
1318               Configuration currentConfig = context.getResources().getConfiguration();                             
1319               if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1320                     Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1321                         + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1322                     forceReload();                                                                                 
1323               }                                                                                                    
1324               // Update previousConfig                                                                             
1325               mPreviousConfigMcc = currentConfig.mcc;                                                              
1326          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1327                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1328              Callbacks callbacks = getCallback();                                                                  
1329              if (callbacks != null) {                                                                              
1330                  callbacks.bindSearchablesChanged();                                                               
1331              }                                                                                                     



1332          }                                                                                                         
1333      }                                                                                                             
1334                                                                                                                    
1335      void forceReload() {                                                                                          
1336          resetLoadedState(true, true);                                                                             
1337                                                                                                                    
1338          // Do this here because if the launcher activity is running it will be restarted.                         
1339          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1340          // to reload.                                                                                             
1341          startLoaderFromBackground();                                                                              
1342      }                                                                                                             
1343                                                                                                                    
1344      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1345          synchronized (mLock) {                                                                                    
1346              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1347              // mWorkspaceLoaded to true later                                                                     
1348              stopLoaderLocked();                                                                                   
1349              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1350              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1351          }                                                                                                         
1352      }                                                                                                             
1353                                                                                                                    
1354      /**                                                                                                           
1355       * When the launcher is in the background, it's possible for it to miss paired                                
1356       * configuration changes.  So whenever we trigger the loader from the background                              
1357       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1358       * of doing it now.                                                                                           
1359       */                                                                                                           
1360      public void startLoaderFromBackground() {                                                                     
1361          boolean runLoader = false;                                                                                
1362          Callbacks callbacks = getCallback();                                                                      
1363          if (callbacks != null) {                                                                                  
1364              // Only actually run the loader if they're not paused.                                                
1365              if (!callbacks.setLoadOnResume()) {                                                                   
1366                  runLoader = true;                                                                                 
1367              }                                                                                                     
1368          }                                                                                                         
1369          if (runLoader) {                                                                                          
1370              startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1371          }                                                                                                         
1372      }                                                                                                             
1373                                                                                                                    
1374      // If there is already a loader task running, tell it to stop.                                                
1375      // returns true if isLaunching() was true on the old task                                                     
1376      private boolean stopLoaderLocked() {                                                                          
1377          boolean isLaunching = false;                                                                              








1378          LoaderTask oldTask = mLoaderTask;                                                                         
1379          if (oldTask != null) {                                                                                    
1380              if (oldTask.isLaunching()) {                                                                          
1381                  isLaunching = true;                                                                               
1382              }                                                                                                     
1383              oldTask.stopLocked();                                                                                 
1384          }                                                                                                         
1385          return isLaunching;                                                                                       
1386      }                                                                                                             
1387                                                                                                                    
1388      public boolean isCurrentCallbacks(Callbacks callbacks) {                                                      
1389          return (mCallbacks != null && mCallbacks.get() == callbacks);                                             
1390      }                                                                                                             
1391                                                                                                                    
1392      public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1393          startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1394      }                                                                                                             
1395                                                                                                                    
1396      public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        







1397          synchronized (mLock) {                                                                                    
1398              if (DEBUG_LOADERS) {                                                                                  
1399                  Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1400              }                                                                                                     
1401                                                                                                                    
1402              // Clear any deferred bind-runnables from the synchronized load process                               
1403              // We must do this before any loading/binding is scheduled below.                                     
1404              synchronized (mDeferredBindRunnables) {                                                               
1405                  mDeferredBindRunnables.clear();                                                                   
1406              }                                                                                                     
1407                                                                                                                    
1408              // Don't bother to start the thread if we know it's not going to do anything                          
1409              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1410                  // If there is already one running, tell it to stop.                                              
1411                  // also, don't downgrade isLaunching if we're already running                                     
1412                  isLaunching = isLaunching || stopLoaderLocked();                                                  
1413                  mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          


1414                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1415                          && mAllAppsLoaded && mWorkspaceLoaded) {                                                  

1416                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1417                  } else {                                                                                          
1418                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1419                      sWorker.post(mLoaderTask);                                                                    
1420                  }                                                                                                 
1421              }                                                                                                     
1422          }                                                                                                         
1423      }                                                                                                             
1424                                                                                                                    
1425      void bindRemainingSynchronousPages() {                                                                        
1426          // Post the remaining side pages to be loaded                                                             
1427          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1428              Runnable[] deferredBindRunnables = null;                                                              
1429              synchronized (mDeferredBindRunnables) {                                                               
1430                  deferredBindRunnables = mDeferredBindRunnables.toArray(                                           
1431                          new Runnable[mDeferredBindRunnables.size()]);                                             
1432                  mDeferredBindRunnables.clear();                                                                   
1433              }                                                                                                     
1434              for (final Runnable r : deferredBindRunnables) {                                                      
1435                  mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   











1436              }                                                                                                     
1437          }                                                                                                         
1438      }                                                                                                             
1439                                                                                                                    
1440      public void stopLoader() {                                                                                    
1441          synchronized (mLock) {                                                                                    
1442              if (mLoaderTask != null) {                                                                            
1443                  mLoaderTask.stopLocked();                                                                         
1444              }                                                                                                     
1445          }                                                                                                         
1446      }                                                                                                             
1447                                                                                                                    
1448      /** Loads the workspace screens db into a map of Rank -> ScreenId */                                          
1449      private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                               




1450          final ContentResolver contentResolver = context.getContentResolver();                                     
1451          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1452          final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                              
1453          TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                                     
1454                                                                                                                    





1455          try {                                                                                                     
1456              final int idIndex = sc.getColumnIndexOrThrow(                                                         
1457                      LauncherSettings.WorkspaceScreens._ID);                                                       
1458              final int rankIndex = sc.getColumnIndexOrThrow(                                                       
1459                      LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                               

1460              while (sc.moveToNext()) {                                                                             
1461                  try {                                                                                             
1462                      long screenId = sc.getLong(idIndex);                                                          
1463                      int rank = sc.getInt(rankIndex);                                                              
1464                      orderedScreens.put(rank, screenId);                                                           

1465                  } catch (Exception e) {                                                                           
1466                      Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);  


1467                  }                                                                                                 
1468              }                                                                                                     
1469          } finally {                                                                                               
1470              sc.close();                                                                                           
1471          }                                                                                                         
1472                                                                                                                    
1473          // Log to disk                                                                                            
1474          Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                                    
1475          ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                           
1476          for (Integer i : orderedScreens.keySet()) {                                                               
1477              orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                              
1478          }                                                                                                         
1479          Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                                       
1480                  TextUtils.join(", ", orderedScreensPairs), true);                                                 
1481          return orderedScreens;                                                                                    

1482      }                                                                                                             
1483                                                                                                                    
1484      public boolean isAllAppsLoaded() {                                                                            
1485          return mAllAppsLoaded;                                                                                    
1486      }                                                                                                             
1487                                                                                                                    
1488      boolean isLoadingWorkspace() {                                                                                
1489          synchronized (mLock) {                                                                                    
1490              if (mLoaderTask != null) {                                                                            
1491                  return mLoaderTask.isLoadingWorkspace();                                                          
1492              }                                                                                                     
1493          }                                                                                                         
1494          return false;                                                                                             
1495      }                                                                                                             
1496                                                                                                                    
1497      /**                                                                                                           
1498       * Runnable for the thread that loads the contents of the launcher:                                           
1499       *   - workspace icons                                                                                        
1500       *   - widgets                                                                                                
1501       *   - all apps icons                                                                                         
1502       */                                                                                                           
1503      private class LoaderTask implements Runnable {                                                                
1504          private Context mContext;                                                                                 
1505          private boolean mIsLaunching;                                                                             
1506          private boolean mIsLoadingAndBindingWorkspace;                                                            

1507          private boolean mStopped;                                                                                 
1508          private boolean mLoadAndBindStepFinished;                                                                 

1509          private int mFlags;                                                                                       
1510                                                                                                                    
1511          private HashMap<Object, CharSequence> mLabelCache;                                                        
1512                                                                                                                    
1513          LoaderTask(Context context, boolean isLaunching, int flags) {                                             

1514              mContext = context;                                                                                   
1515              mIsLaunching = isLaunching;                                                                           
1516              mLabelCache = new HashMap<Object, CharSequence>();                                                    
1517              mFlags = flags;                                                                                       
1518          }                                                                                                         
1519                                                                                                                    
1520          boolean isLaunching() {                                                                                   
1521              return mIsLaunching;                                                                                  
1522          }                                                                                                         
1523                                                                                                                    
1524          boolean isLoadingWorkspace() {                                                                            
1525              return mIsLoadingAndBindingWorkspace;                                                                 
1526          }                                                                                                         
1527                                                                                                                    
1528          /** Returns whether this is an upgrade path */                                                            
1529          private boolean loadAndBindWorkspace() {                                                                  

1530              mIsLoadingAndBindingWorkspace = true;                                                                 
1531                                                                                                                    
1532              // Load the workspace                                                                                 
1533              if (DEBUG_LOADERS) {                                                                                  
1534                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1535              }                                                                                                     
1536                                                                                                                    
1537              boolean isUpgradePath = false;                                                                        
1538              if (!mWorkspaceLoaded) {                                                                              
1539                  isUpgradePath = loadWorkspace();                                                                  

1540                  synchronized (LoaderTask.this) {                                                                  
1541                      if (mStopped) {                                                                               
1542                          return isUpgradePath;                                                                     

1543                      }                                                                                             
1544                      mWorkspaceLoaded = true;                                                                      
1545                  }                                                                                                 
1546              }                                                                                                     
1547                                                                                                                    
1548              // Bind the workspace                                                                                 
1549              bindWorkspace(-1, isUpgradePath);                                                                     
1550              return isUpgradePath;                                                                                 

1551          }                                                                                                         
1552                                                                                                                    
1553          private void waitForIdle() {                                                                              
1554              // Wait until the either we're stopped or the other threads are done.                                 
1555              // This way we don't start loading all apps until the workspace has settled                           
1556              // down.                                                                                              
1557              synchronized (LoaderTask.this) {                                                                      
1558                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1559                                                                                                                    
1560                  mHandler.postIdle(new Runnable() {                                                                
1561                          public void run() {                                                                       
1562                              synchronized (LoaderTask.this) {                                                      
1563                                  mLoadAndBindStepFinished = true;                                                  
1564                                  if (DEBUG_LOADERS) {                                                              
1565                                      Log.d(TAG, "done with previous binding step");                                
1566                                  }                                                                                 
1567                                  LoaderTask.this.notify();                                                         
1568                              }                                                                                     
1569                          }                                                                                         
1570                      });                                                                                           
1571                                                                                                                    
1572                  while (!mStopped && !mLoadAndBindStepFinished) {                                                  
1573                      try {                                                                                         
1574                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1575                          // wait no longer than 1sec at a time                                                     
1576                          this.wait(1000);                                                                          
1577                      } catch (InterruptedException ex) {                                                           
1578                          // Ignore                                                                                 
1579                      }                                                                                             
1580                  }                                                                                                 
1581                  if (DEBUG_LOADERS) {                                                                              
1582                      Log.d(TAG, "waited "                                                                          
1583                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1584                              + "ms for previous step to finish binding");                                          
1585                  }                                                                                                 
1586              }                                                                                                     
1587          }                                                                                                         
1588                                                                                                                    
1589          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1590              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1591                  // Ensure that we have a valid page index to load synchronously                                   
1592                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1593                          "valid page index");                                                                      
1594              }                                                                                                     
1595              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1596                  // Ensure that we don't try and bind a specified page when the pages have not been                
1597                  // loaded already (we should load everything asynchronously in that case)                         
1598                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1599              }                                                                                                     
1600              synchronized (mLock) {                                                                                
1601                  if (mIsLoaderTaskRunning) {                                                                       
1602                      // Ensure that we are never running the background loading at this point since                
1603                      // we also touch the background collections                                                   
1604                      throw new RuntimeException("Error! Background loading is already running");                   
1605                  }                                                                                                 
1606              }                                                                                                     
1607                                                                                                                    
1608              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1609              //      data structures, we can't allow any other thread to touch that data, but because              
1610              //      this call is synchronous, we can get away with not locking).                                  
1611                                                                                                                    
1612              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1613              // operations from the previous activity.  We need to ensure that all queued operations               
1614              // are executed before any synchronous binding work is done.                                          
1615              mHandler.flush();                                                                                     
1616                                                                                                                    
1617              // Divide the set of loaded items into those that we are binding synchronously, and                   
1618              // everything else that is to be bound normally (asynchronously).                                     
1619              bindWorkspace(synchronousBindPage, false);                                                            

1620              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1621              //      arise from that.                                                                              
1622              onlyBindAllApps();                                                                                    
1623          }                                                                                                         
1624                                                                                                                    
1625          public void run() {                                                                                       
1626              boolean isUpgrade = false;                                                                            
1627                                                                                                                    
1628              synchronized (mLock) {                                                                                



1629                  mIsLoaderTaskRunning = true;                                                                      
1630              }                                                                                                     
1631              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1632              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1633              // workspace first (default).                                                                         
1634              keep_running: {                                                                                       
1635                  // Elevate priority when Home launches for the first time to avoid                                
1636                  // starving at boot time. Staring at a blank home is not cool.                                    
1637                  synchronized (mLock) {                                                                            
1638                      if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1639                              (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1640                      android.os.Process.setThreadPriority(mIsLaunching                                             
1641                              ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1642                  }                                                                                                 
1643                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1644                  isUpgrade = loadAndBindWorkspace();                                                               

1645                                                                                                                    
1646                  if (mStopped) {                                                                                   
1647                      break keep_running;                                                                           
1648                  }                                                                                                 
1649                                                                                                                    
1650                  // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1651                  // settled down.                                                                                  
1652                  synchronized (mLock) {                                                                            
1653                      if (mIsLaunching) {                                                                           
1654                          if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1655                          android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1656                      }                                                                                             
1657                  }                                                                                                 
1658                  waitForIdle();                                                                                    
1659                                                                                                                    
1660                  // second step                                                                                    
1661                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1662                  loadAndBindAllApps();                                                                             
1663                                                                                                                    
1664                  // Restore the default thread priority after we are done loading items                            
1665                  synchronized (mLock) {                                                                            
1666                      android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1667                  }                                                                                                 
1668              }                                                                                                     
1669                                                                                                                    
1670              // Update the saved icons if necessary                                                                
1671              if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1672              synchronized (sBgLock) {                                                                              
1673                  for (Object key : sBgDbIconCache.keySet()) {                                                      
1674                      updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1675                  }                                                                                                 
1676                  sBgDbIconCache.clear();                                                                           
1677              }                                                                                                     
1678                                                                                                                    
1679              if (LauncherAppState.isDisableAllApps()) {                                                            
1680                  // Ensure that all the applications that are in the system are                                    
1681                  // represented on the home screen.                                                                
1682                  if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                                
1683                      verifyApplications();                                                                         
1684                  }                                                                                                 
1685              }                                                                                                     
1686                                                                                                                    
1687              // Clear out this reference, otherwise we end up holding it until all of the                          
1688              // callback runnables are done.                                                                       
1689              mContext = null;                                                                                      
1690                                                                                                                    
1691              synchronized (mLock) {                                                                                
1692                  // If we are still the last one to be scheduled, remove ourselves.                                
1693                  if (mLoaderTask == this) {                                                                        
1694                      mLoaderTask = null;                                                                           
1695                  }                                                                                                 
1696                  mIsLoaderTaskRunning = false;                                                                     

1697              }                                                                                                     
1698          }                                                                                                         
1699                                                                                                                    
1700          public void stopLocked() {                                                                                
1701              synchronized (LoaderTask.this) {                                                                      
1702                  mStopped = true;                                                                                  
1703                  this.notify();                                                                                    
1704              }                                                                                                     
1705          }                                                                                                         
1706                                                                                                                    
1707          /**                                                                                                       
1708           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
1709           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
1710           * object that was around when the deferred message was scheduled, and if there's                         
1711           * a new Callbacks object around then also return null.  This will save us from                           
1712           * calling onto it with data that will be ignored.                                                        
1713           */                                                                                                       
1714          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
1715              synchronized (mLock) {                                                                                
1716                  if (mStopped) {                                                                                   
1717                      return null;                                                                                  
1718                  }                                                                                                 
1719                                                                                                                    
1720                  if (mCallbacks == null) {                                                                         
1721                      return null;                                                                                  
1722                  }                                                                                                 
1723                                                                                                                    
1724                  final Callbacks callbacks = mCallbacks.get();                                                     
1725                  if (callbacks != oldCallbacks) {                                                                  
1726                      return null;                                                                                  
1727                  }                                                                                                 
1728                  if (callbacks == null) {                                                                          
1729                      Log.w(TAG, "no mCallbacks");                                                                  
1730                      return null;                                                                                  
1731                  }                                                                                                 
1732                                                                                                                    
1733                  return callbacks;                                                                                 
1734              }                                                                                                     
1735          }                                                                                                         
1736                                                                                                                    
1737          private void verifyApplications() {                                                                       
1738              final Context context = mApp.getContext();                                                            
1739                                                                                                                    
1740              // Cross reference all the applications in our apps list with items in the workspace                  
1741              ArrayList<ItemInfo> tmpInfos;                                                                         
1742              ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
1743              synchronized (sBgLock) {                                                                              
1744                  for (AppInfo app : mBgAllAppsList.data) {                                                         
1745                      tmpInfos = getItemInfoForComponentName(app.componentName, app.user);                          
1746                      if (tmpInfos.isEmpty()) {                                                                     
1747                          // We are missing an application icon, so add this to the workspace                       
1748                          added.add(app);                                                                           
1749                          // This is a rare event, so lets log it                                                   
1750                          Log.e(TAG, "Missing Application on load: " + app);                                        
1751                      }                                                                                             
1752                  }                                                                                                 
1753              }                                                                                                     
1754              if (!added.isEmpty()) {                                                                               
1755                  addAndBindAddedWorkspaceApps(context, added);                                                     
1756              }                                                                                                     
1757          }                                                                                                         
1758                                                                                                                    
1759          // check & update map of what's occupied; used to discard overlapping/invalid items                       
1760          private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {                 

1761              LauncherAppState app = LauncherAppState.getInstance();                                                
1762              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1763              final int countX = (int) grid.numColumns;                                                             
1764              final int countY = (int) grid.numRows;                                                                



1765                                                                                                                    
1766              long containerIndex = item.screenId;                                                                  
1767              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1768                  // Return early if we detect that an item is under the hotseat button                             
1769                  if (mCallbacks == null ||                                                                         
1770                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
1771                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
1772                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
1773                              + item.cellY + ") occupied by all apps");                                             
1774                      return false;                                                                                 
1775                  }                                                                                                 
1776                                                                                                                    
1777                  final ItemInfo[][] hotseatItems =                                                                 
1778                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
1779                                                                                                                    
1780                  if (item.screenId >= grid.numHotseatIcons) {                                                      

1781                      Log.e(TAG, "Error loading shortcut " + item                                                   
1782                              + " into hotseat position " + item.screenId                                           
1783                              + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     

1784                              + ")");                                                                               
1785                      return false;                                                                                 
1786                  }                                                                                                 
1787                                                                                                                    
1788                  if (hotseatItems != null) {                                                                       
1789                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
1790                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
1791                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
1792                                  + item.cellY + ") occupied by "                                                   
1793                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
1794                                  [(int) item.screenId][0]);                                                        
1795                              return false;                                                                         
1796                      } else {                                                                                      
1797                          hotseatItems[(int) item.screenId][0] = item;                                              
1798                          return true;                                                                              
1799                      }                                                                                             
1800                  } else {                                                                                          
1801                      final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       

1802                      items[(int) item.screenId][0] = item;                                                         
1803                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
1804                      return true;                                                                                  
1805                  }                                                                                                 
1806              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
1807                  // Skip further checking if it is not the hotseat or workspace container                          
1808                  return true;                                                                                      
1809              }                                                                                                     
1810                                                                                                                    
1811              if (!occupied.containsKey(item.screenId)) {                                                           
1812                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
1813                  occupied.put(item.screenId, items);                                                               
1814              }                                                                                                     
1815                                                                                                                    
1816              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
1817              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
1818                      item.cellX < 0 || item.cellY < 0 ||                                                           
1819                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
1820                  Log.e(TAG, "Error loading shortcut " + item                                                       
1821                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
1822                          + item.cellX + "," + item.cellY                                                           
1823                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
1824                  return false;                                                                                     
1825              }                                                                                                     
1826                                                                                                                    
1827              // Check if any workspace icons overlap with each other                                               
1828              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1829                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1830                      if (screens[x][y] != null) {                                                                  
1831                          Log.e(TAG, "Error loading shortcut " + item                                               
1832                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
1833                              + x + "," + y                                                                         
1834                              + ") occupied by "                                                                    
1835                              + screens[x][y]);                                                                     
1836                          return false;                                                                             
1837                      }                                                                                             
1838                  }                                                                                                 
1839              }                                                                                                     
1840              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1841                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1842                      screens[x][y] = item;                                                                         
1843                  }                                                                                                 
1844              }                                                                                                     
1845                                                                                                                    
1846              return true;                                                                                          
1847          }                                                                                                         
1848                                                                                                                    
1849          /** Clears all the sBg data structures */                                                                 
1850          private void clearSBgDataStructures() {                                                                   
1851              synchronized (sBgLock) {                                                                              
1852                  sBgWorkspaceItems.clear();                                                                        
1853                  sBgAppWidgets.clear();                                                                            
1854                  sBgFolders.clear();                                                                               
1855                  sBgItemsIdMap.clear();                                                                            
1856                  sBgDbIconCache.clear();                                                                           
1857                  sBgWorkspaceScreens.clear();                                                                      
1858              }                                                                                                     
1859          }                                                                                                         
1860                                                                                                                    
1861          /** Returns whether this is an upgrade path */                                                            
1862          private boolean loadWorkspace() {                                                                         
1863              // Log to disk                                                                                        
1864              Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
1865                                                                                                                    

1866              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
1867                                                                                                                    
1868              final Context context = mContext;                                                                     
1869              final ContentResolver contentResolver = context.getContentResolver();                                 
1870              final PackageManager manager = context.getPackageManager();                                           
1871              final boolean isSafeMode = manager.isSafeMode();                                                      
1872              final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                      
1873              final boolean isSdCardReady = context.registerReceiver(null,                                          
1874                      new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                                      
1875                                                                                                                    
1876              LauncherAppState app = LauncherAppState.getInstance();                                                
1877              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1878              int countX = (int) grid.numColumns;                                                                   
1879              int countY = (int) grid.numRows;                                                                      



1880                                                                                                                    
1881              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
1882                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
1883                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
1884              }                                                                                                     
1885                                                                                                                    
1886              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
1887                  // append the user's Launcher2 shortcuts                                                          
1888                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
1889                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
1890              } else {                                                                                              
1891                  // Make sure the default workspace is loaded                                                      
1892                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
1893                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                         
1894              }                                                                                                     
1895                                                                                                                    
1896              // This code path is for our old migration code and should no longer be exercised                     
1897              boolean loadedOldDb = false;                                                                          
1898                                                                                                                    
1899              // Log to disk                                                                                        
1900              Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                           
1901                                                                                                                    
1902              synchronized (sBgLock) {                                                                              
1903                  clearSBgDataStructures();                                                                         
1904                  final HashSet<String> installingPkgs = PackageInstallerCompat                                     

1905                          .getInstance(mContext).updateAndGetActiveSessionCache();                                  
1906                                                                                                                    
1907                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
1908                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
1909                  final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;                    

1910                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
1911                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
1912                                                                                                                    
1913                  // +1 for the hotseat (it can be larger than the workspace)                                       
1914                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
1915                  // before any earlier duplicates)                                                                 
1916                  final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   

1917                                                                                                                    
1918                  try {                                                                                             
1919                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
1920                      final int intentIndex = c.getColumnIndexOrThrow                                               
1921                              (LauncherSettings.Favorites.INTENT);                                                  
1922                      final int titleIndex = c.getColumnIndexOrThrow                                                
1923                              (LauncherSettings.Favorites.TITLE);                                                   
1924                      final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
1925                              LauncherSettings.Favorites.ICON_TYPE);                                                
1926                      final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
1927                      final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
1928                              LauncherSettings.Favorites.ICON_PACKAGE);                                             
1929                      final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
1930                              LauncherSettings.Favorites.ICON_RESOURCE);                                            
1931                      final int containerIndex = c.getColumnIndexOrThrow(                                           
1932                              LauncherSettings.Favorites.CONTAINER);                                                
1933                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
1934                              LauncherSettings.Favorites.ITEM_TYPE);                                                
1935                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
1936                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
1937                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
1938                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
1939                      final int screenIndex = c.getColumnIndexOrThrow(                                              
1940                              LauncherSettings.Favorites.SCREEN);                                                   
1941                      final int cellXIndex = c.getColumnIndexOrThrow                                                
1942                              (LauncherSettings.Favorites.CELLX);                                                   
1943                      final int cellYIndex = c.getColumnIndexOrThrow                                                
1944                              (LauncherSettings.Favorites.CELLY);                                                   
1945                      final int spanXIndex = c.getColumnIndexOrThrow                                                
1946                              (LauncherSettings.Favorites.SPANX);                                                   
1947                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
1948                              LauncherSettings.Favorites.SPANY);                                                    
1949                      final int rankIndex = c.getColumnIndexOrThrow(                                                
1950                              LauncherSettings.Favorites.RANK);                                                     
1951                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
1952                              LauncherSettings.Favorites.RESTORED);                                                 
1953                      final int profileIdIndex = c.getColumnIndexOrThrow(                                           
1954                              LauncherSettings.Favorites.PROFILE_ID);                                               
1955                      //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
1956                      //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
1957                      //        LauncherSettings.Favorites.DISPLAY_MODE);                                           








1958                                                                                                                    
1959                      ShortcutInfo info;                                                                            
1960                      String intentDescription;                                                                     
1961                      LauncherAppWidgetInfo appWidgetInfo;                                                          
1962                      int container;                                                                                
1963                      long id;                                                                                      
1964                      long serialNumber;                                                                            
1965                      Intent intent;                                                                                
1966                      UserHandleCompat user;                                                                        
1967                                                                                                                    
1968                      while (!mStopped && c.moveToNext()) {                                                         
1969                          try {                                                                                     
1970                              int itemType = c.getInt(itemTypeIndex);                                               
1971                              boolean restored = 0 != c.getInt(restoredIndex);                                      
1972                              boolean allowMissingTarget = false;                                                   

1973                                                                                                                    
1974                              switch (itemType) {                                                                   
1975                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1976                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1977                                  id = c.getLong(idIndex);                                                          
1978                                  intentDescription = c.getString(intentIndex);                                     
1979                                  serialNumber = c.getInt(profileIdIndex);                                          
1980                                  user = mUserManager.getUserForSerialNumber(serialNumber);                         

1981                                  int promiseType = c.getInt(restoredIndex);                                        
1982                                  int disabledState = 0;                                                            

1983                                  if (user == null) {                                                               
1984                                      // User has been deleted remove the item.                                     
1985                                      itemsToRemove.add(id);                                                        
1986                                      continue;                                                                     
1987                                  }                                                                                 
1988                                  try {                                                                             
1989                                      intent = Intent.parseUri(intentDescription, 0);                               
1990                                      ComponentName cn = intent.getComponent();                                     
1991                                      if (cn != null && cn.getPackageName() != null) {                              
1992                                          boolean validPkg = launcherApps.isPackageEnabledForProfile(               
1993                                                  cn.getPackageName(), user);                                       
1994                                          boolean validComponent = validPkg &&                                      
1995                                                  launcherApps.isActivityEnabledForProfile(cn, user);               
1996                                                                                                                    
1997                                          if (validComponent) {                                                     
1998                                              if (restored) {                                                       
1999                                                  // no special handling necessary for this item                    
2000                                                  restoredRows.add(id);                                             
2001                                                  restored = false;                                                 
2002                                              }                                                                     
2003                                          } else if (validPkg) {                                                    
2004                                              intent = null;                                                        
2005                                              if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {         
2006                                                  // We allow auto install apps to have their intent                
2007                                                  // updated after an install.                                      
2008                                                  intent = manager.getLaunchIntentForPackage(                       
2009                                                          cn.getPackageName());                                     
2010                                                  if (intent != null) {                                             
2011                                                      ContentValues values = new ContentValues();                   
2012                                                      values.put(LauncherSettings.Favorites.INTENT,                 
2013                                                              intent.toUri(0));                                     
2014                                                      String where = BaseColumns._ID + "= ?";                       
2015                                                      String[] args = {Long.toString(id)};                          
2016                                                      contentResolver.update(contentUri, values, where, args);      

2017                                                  }                                                                 
2018                                              }                                                                     
2019                                                                                                                    
2020                                              if (intent == null) {                                                 
2021                                                  // The app is installed but the component is no                   
2022                                                  // longer available.                                              
2023                                                  Launcher.addDumpLog(TAG,                                          
2024                                                          "Invalid component removed: " + cn, true);                
2025                                                  itemsToRemove.add(id);                                            
2026                                                  continue;                                                         
2027                                              } else {                                                              
2028                                                  // no special handling necessary for this item                    
2029                                                  restoredRows.add(id);                                             
2030                                                  restored = false;                                                 
2031                                              }                                                                     
2032                                          } else if (restored) {                                                    
2033                                              // Package is not yet available but might be                          
2034                                              // installed later.                                                   
2035                                              Launcher.addDumpLog(TAG,                                              
2036                                                      "package not yet restored: " + cn, true);                     
2037                                                                                                                    
2038                                              if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {         
2039                                                  // Restore has started once.                                      
2040                                              } else if (installingPkgs.contains(cn.getPackageName())) {            

2041                                                  // App restore has started. Update the flag                       
2042                                                  promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;                 
2043                                                  ContentValues values = new ContentValues();                       
2044                                                  values.put(LauncherSettings.Favorites.RESTORED,                   
2045                                                          promiseType);                                             
2046                                                  String where = BaseColumns._ID + "= ?";                           
2047                                                  String[] args = {Long.toString(id)};                              
2048                                                  contentResolver.update(contentUri, values, where, args);          
2049                                                                                                                    





















2050                                              } else if (REMOVE_UNRESTORED_ICONS) {                                 
2051                                                  Launcher.addDumpLog(TAG,                                          
2052                                                          "Unrestored package removed: " + cn, true);               
2053                                                  itemsToRemove.add(id);                                            
2054                                                  continue;                                                         
2055                                              }                                                                     
2056                                          } else if (launcherApps.isAppEnabled(                                     
2057                                                  manager, cn.getPackageName(),                                     
2058                                                  PackageManager.GET_UNINSTALLED_PACKAGES)) {                       
2059                                              // Package is present but not available.                              
2060                                              allowMissingTarget = true;                                            
2061                                              disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;             
2062                                          } else if (!isSdCardReady) {                                              
2063                                              // SdCard is not ready yet. Package might get available,              
2064                                              // once it is ready.                                                  
2065                                              Launcher.addDumpLog(TAG, "Invalid package: " + cn                     
2066                                                      + " (check again later)", true);                              
2067                                              HashSet<String> pkgs = sPendingPackages.get(user);                    
2068                                              if (pkgs == null) {                                                   
2069                                                  pkgs = new HashSet<String>();                                     
2070                                                  sPendingPackages.put(user, pkgs);                                 
2071                                              }                                                                     
2072                                              pkgs.add(cn.getPackageName());                                        
2073                                              allowMissingTarget = true;                                            
2074                                              // Add the icon on the workspace anyway.                              
2075                                                                                                                    
2076                                          } else {                                                                  
2077                                              // Do not wait for external media load anymore.                       
2078                                              // Log the invalid package, and remove it                             
2079                                              Launcher.addDumpLog(TAG,                                              
2080                                                      "Invalid package removed: " + cn, true);                      
2081                                              itemsToRemove.add(id);                                                
2082                                              continue;                                                             
2083                                          }                                                                         
2084                                      } else if (cn == null) {                                                      
2085                                          // For shortcuts with no component, keep them as they are                 
2086                                          restoredRows.add(id);                                                     
2087                                          restored = false;                                                         
2088                                      }                                                                             
2089                                  } catch (URISyntaxException e) {                                                  
2090                                      Launcher.addDumpLog(TAG,                                                      
2091                                              "Invalid uri: " + intentDescription, true);                           
2092                                      continue;                                                                     
2093                                  }                                                                                 
2094                                                                                                                    
2095                                  if (restored) {                                                                   














2096                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2097                                          Launcher.addDumpLog(TAG,                                                  
2098                                                  "constructing info for partially restored package",               
2099                                                  true);                                                            
2100                                          info = getRestoredItemInfo(c, titleIndex, intent, promiseType);           


2101                                          intent = getRestoredItemIntent(c, context, intent);                       
2102                                      } else {                                                                      
2103                                          // Don't restore items for other profiles.                                
2104                                          itemsToRemove.add(id);                                                    
2105                                          continue;                                                                 
2106                                      }                                                                             
2107                                  } else if (itemType ==                                                            
2108                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
2109                                      info = getShortcutInfo(manager, intent, user, context, c,                     
2110                                              iconIndex, titleIndex, mLabelCache, allowMissingTarget);              



2111                                  } else {                                                                          
2112                                      info = getShortcutInfo(c, context, iconTypeIndex,                             
2113                                              iconPackageIndex, iconResourceIndex, iconIndex,                       
2114                                              titleIndex);                                                          

2115                                                                                                                    
2116                                      // App shortcuts that used to be automatically added to Launcher              
2117                                      // didn't always have the correct intent flags set, so do that                
2118                                      // here                                                                       
2119                                      if (intent.getAction() != null &&                                             
2120                                          intent.getCategories() != null &&                                         
2121                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
2122                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
2123                                          intent.addFlags(                                                          
2124                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
2125                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
2126                                      }                                                                             
2127                                  }                                                                                 
2128                                                                                                                    
2129                                  if (info != null) {                                                               
2130                                      info.id = id;                                                                 
2131                                      info.intent = intent;                                                         
2132                                      container = c.getInt(containerIndex);                                         
2133                                      info.container = container;                                                   
2134                                      info.screenId = c.getInt(screenIndex);                                        
2135                                      info.cellX = c.getInt(cellXIndex);                                            
2136                                      info.cellY = c.getInt(cellYIndex);                                            
2137                                      info.rank = c.getInt(rankIndex);                                              
2138                                      info.spanX = 1;                                                               
2139                                      info.spanY = 1;                                                               
2140                                      info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);                   



2141                                      info.isDisabled = disabledState;                                              
2142                                      if (isSafeMode && !Utilities.isSystemApp(context, intent)) {                  
2143                                          info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;                   
2144                                      }                                                                             
2145                                                                                                                    
2146                                      // check & update map of what's occupied                                      
2147                                      if (!checkItemPlacement(occupied, info)) {                                    
2148                                          itemsToRemove.add(id);                                                    
2149                                          break;                                                                    












2150                                      }                                                                             
2151                                                                                                                    
2152                                      switch (container) {                                                          
2153                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2154                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2155                                          sBgWorkspaceItems.add(info);                                              
2156                                          break;                                                                    
2157                                      default:                                                                      
2158                                          // Item is in a user folder                                               
2159                                          FolderInfo folderInfo =                                                   
2160                                                  findOrMakeFolder(sBgFolders, container);                          
2161                                          folderInfo.add(info);                                                     
2162                                          break;                                                                    
2163                                      }                                                                             
2164                                      sBgItemsIdMap.put(info.id, info);                                             
2165                                                                                                                    
2166                                      // now that we've loaded everthing re-save it with the                        
2167                                      // icon in case it disappears somehow.                                        
2168                                      queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
2169                                  } else {                                                                          
2170                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
2171                                  }                                                                                 
2172                                  break;                                                                            
2173                                                                                                                    
2174                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
2175                                  id = c.getLong(idIndex);                                                          
2176                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
2177                                                                                                                    

2178                                  folderInfo.title = c.getString(titleIndex);                                       
2179                                  folderInfo.id = id;                                                               
2180                                  container = c.getInt(containerIndex);                                             
2181                                  folderInfo.container = container;                                                 
2182                                  folderInfo.screenId = c.getInt(screenIndex);                                      
2183                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
2184                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
2185                                  folderInfo.spanX = 1;                                                             
2186                                  folderInfo.spanY = 1;                                                             

2187                                                                                                                    
2188                                  // check & update map of what's occupied                                          
2189                                  if (!checkItemPlacement(occupied, folderInfo)) {                                  
2190                                      itemsToRemove.add(id);                                                        
2191                                      break;                                                                        
2192                                  }                                                                                 
2193                                                                                                                    
2194                                  switch (container) {                                                              
2195                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2196                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2197                                          sBgWorkspaceItems.add(folderInfo);                                        
2198                                          break;                                                                    
2199                                  }                                                                                 
2200                                                                                                                    
2201                                  if (restored) {                                                                   
2202                                      // no special handling required for restored folders                          
2203                                      restoredRows.add(id);                                                         
2204                                  }                                                                                 
2205                                                                                                                    
2206                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
2207                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
2208                                  break;                                                                            
2209                                                                                                                    
2210                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
2211                              case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                           
2212                                  // Read all Launcher-specific widget details                                      
2213                                  boolean customWidget = itemType ==                                                
2214                                      LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;                        
2215                                                                                                                    
2216                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
2217                                  serialNumber= c.getLong(profileIdIndex);                                          
2218 +                                user = mUserManager.getUserForSerialNumber(serialNumber);                         
2219 +                                if (user == null) {                                                               
2220 +                                    // User has been deleted remove the item.                                     
2221 +                                    itemsToRemove.add(id);                                                        
2222 +                                    continue;                                                                     
2223 +                                }                                                                                 
2224                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
2225                                  id = c.getLong(idIndex);                                                          






2226                                  final ComponentName component =                                                   
2227                                          ComponentName.unflattenFromString(savedProvider);                         
2228                                                                                                                    
2229                                  final int restoreStatus = c.getInt(restoredIndex);                                
2230                                  final boolean isIdValid = (restoreStatus &                                        
2231                                          LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                            
2232                                                                                                                    
2233                                  final boolean wasProviderReady = (restoreStatus &                                 
2234                                          LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;                      
2235                                                                                                                    
2236                                  final LauncherAppWidgetProviderInfo provider =                                    
2237                                          LauncherModel.getProviderInfo(context,                                    
2238                                                  ComponentName.unflattenFromString(savedProvider),                 
2239 -                                                mUserManager.getUserForSerialNumber(serialNumber));               
2240 +                                                user);                                                            
2241                                                                                                                    
2242                                  final boolean isProviderReady = isValidProvider(provider);                        
2243                                  if (!isSafeMode && !customWidget &&                                               
2244                                          wasProviderReady && !isProviderReady) {                                   
2245                                      String log = "Deleting widget that isn't installed anymore: "                 
2246                                              + "id=" + id + " appWidgetId=" + appWidgetId;                         
2247                                                                                                                    
2248                                      Log.e(TAG, log);                                                              
2249                                      Launcher.addDumpLog(TAG, log, false);                                         
2250                                      itemsToRemove.add(id);                                                        
2251                                  } else {                                                                          
2252                                      if (isProviderReady) {                                                        
2253                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2254                                                  provider.provider);                                               
2255                                                                                                                    
2256                                          if (!customWidget) {                                                      
2257                                              int[] minSpan =                                                       
2258                                                      Launcher.getMinSpanForWidget(context, provider);              
2259                                              appWidgetInfo.minSpanX = minSpan[0];                                  
2260                                              appWidgetInfo.minSpanY = minSpan[1];                                  
2261                                          }                                                                         
2262                                                                                                                    
2263                                          int status = restoreStatus;                                               
2264                                          if (!wasProviderReady) {                                                  
2265                                              // If provider was not previously ready, update the                   
2266                                              // status and UI flag.                                                
2267                                                                                                                    
2268                                              // Id would be valid only if the widget restore broadcast was received🔵
2269                                              if (isIdValid) {                                                      
2270                                                  status = LauncherAppWidgetInfo.RESTORE_COMPLETED;                 
2271                                              } else {                                                              
2272                                                  status &= ~LauncherAppWidgetInfo                                  
2273                                                          .FLAG_PROVIDER_NOT_READY;                                 
2274                                              }                                                                     
2275                                          }                                                                         
2276                                          appWidgetInfo.restoreStatus = status;                                     
2277                                      } else {                                                                      
2278                                          Log.v(TAG, "Widget restore pending id=" + id                              
2279                                                  + " appWidgetId=" + appWidgetId                                   
2280                                                  + " status =" + restoreStatus);                                   
2281                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2282                                                  component);                                                       
2283                                          appWidgetInfo.restoreStatus = restoreStatus;                              

2284                                                                                                                    
2285                                          if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {  
2286                                              // Restore has started once.                                          
2287                                          } else if (installingPkgs.contains(component.getPackageName())) {         

2288                                              // App restore has started. Update the flag                           
2289                                              appWidgetInfo.restoreStatus |=                                        
2290                                                      LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;                   
2291                                          } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {                      
2292                                              Launcher.addDumpLog(TAG,                                              
2293                                                      "Unrestored widget removed: " + component, true);             
2294                                              itemsToRemove.add(id);                                                
2295                                              continue;                                                             
2296                                          }                                                                         



2297                                      }                                                                             
2298                                                                                                                    
2299                                      appWidgetInfo.id = id;                                                        
2300                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
2301                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
2302                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
2303                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
2304                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   
2305 +                                    appWidgetInfo.user = user;                                                    
2306                                                                                                                    
2307                                      if (!customWidget) {                                                          
2308                                          int[] minSpan = Launcher.getMinSpanForWidget(context, provider);          
2309                                          appWidgetInfo.minSpanX = minSpan[0];                                      
2310                                          appWidgetInfo.minSpanY = minSpan[1];                                      
2311                                      }                                                                             
2312                                                                                                                    
2313                                      container = c.getInt(containerIndex);                                         
2314                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
2315                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
2316                                          Log.e(TAG, "Widget found where container != " +                           
2317                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
2318                                          continue;                                                                 
2319                                      }                                                                             
2320                                                                                                                    
2321                                      appWidgetInfo.container = c.getInt(containerIndex);                           

2322                                      // check & update map of what's occupied                                      
2323                                      if (!checkItemPlacement(occupied, appWidgetInfo)) {                           
2324                                          itemsToRemove.add(id);                                                    
2325                                          break;                                                                    
2326                                      }                                                                             
2327                                                                                                                    
2328                                      if (!customWidget) {                                                          
2329                                          String providerName =                                                     
2330                                                  appWidgetInfo.providerName.flattenToString();                     
2331                                          if (!providerName.equals(savedProvider) ||                                
2332                                                  (appWidgetInfo.restoreStatus != restoreStatus)) {                 
2333                                              ContentValues values = new ContentValues();                           
2334                                              values.put(                                                           
2335                                                      LauncherSettings.Favorites.APPWIDGET_PROVIDER,                
2336                                                      providerName);                                                
2337                                              values.put(LauncherSettings.Favorites.RESTORED,                       
2338                                                      appWidgetInfo.restoreStatus);                                 
2339                                              String where = BaseColumns._ID + "= ?";                               
2340                                              String[] args = {Long.toString(id)};                                  
2341                                              contentResolver.update(contentUri, values, where, args);              

2342                                          }                                                                         
2343                                      }                                                                             
2344                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2345                                      sBgAppWidgets.add(appWidgetInfo);                                             
2346                                  }                                                                                 
2347                                  break;                                                                            
2348                              }                                                                                     
2349                          } catch (Exception e) {                                                                   
2350                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2351                          }                                                                                         
2352                      }                                                                                             
2353                  } finally {                                                                                       
2354                      if (c != null) {                                                                              
2355                          c.close();                                                                                
2356                      }                                                                                             
2357                  }                                                                                                 
2358                                                                                                                    
2359                  // Break early if we've stopped loading                                                           
2360                  if (mStopped) {                                                                                   
2361                      clearSBgDataStructures();                                                                     
2362                      return false;                                                                                 

2363                  }                                                                                                 
2364                                                                                                                    
2365                  if (itemsToRemove.size() > 0) {                                                                   
2366                      ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2367                              contentUri);                                                                          
2368                      // Remove dead items                                                                          
2369                      for (long id : itemsToRemove) {                                                               
2370                          if (DEBUG_LOADERS) {                                                                      
2371                              Log.d(TAG, "Removed id = " + id);                                                     
2372                          }                                                                                         
2373                          // Don't notify content observers                                                         
2374                          try {                                                                                     
2375                              client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2376                                      null, null);                                                                  
2377                          } catch (RemoteException e) {                                                             
2378                              Log.w(TAG, "Could not remove id = " + id);                                            
2379                          }                                                                                         














2380                      }                                                                                             
2381                  }                                                                                                 
2382                                                                                                                    
2383                  if (restoredRows.size() > 0) {                                                                    
2384                      ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2385                              contentUri);                                                                          
2386                      // Update restored items that no longer require special handling                              
2387                      try {                                                                                         
2388                          StringBuilder selectionBuilder = new StringBuilder();                                     
2389                          selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2390                          selectionBuilder.append(" IN (");                                                         
2391                          selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2392                          selectionBuilder.append(")");                                                             
2393                          ContentValues values = new ContentValues();                                               
2394                          values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2395                          updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                    
2396                                  values, selectionBuilder.toString(), null);                                       
2397                      } catch (RemoteException e) {                                                                 
2398                          Log.w(TAG, "Could not update restored rows");                                             
2399                      }                                                                                             





2400                  }                                                                                                 
2401                                                                                                                    
2402                  if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                              
2403                      context.registerReceiver(new AppsAvailabilityCheck(),                                         
2404                              new IntentFilter(StartupReceiver.SYSTEM_READY),                                       
2405                              null, sWorker);                                                                       
2406                  }                                                                                                 
2407                                                                                                                    
2408                  if (loadedOldDb) {                                                                                
2409                      long maxScreenId = 0;                                                                         
2410                      // If we're importing we use the old screen order.                                            
2411                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2412                          long screenId = item.screenId;                                                            
2413                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2414                                  !sBgWorkspaceScreens.contains(screenId)) {                                        
2415                              sBgWorkspaceScreens.add(screenId);                                                    
2416                              if (screenId > maxScreenId) {                                                         
2417                                  maxScreenId = screenId;                                                           
2418                              }                                                                                     
2419                          }                                                                                         
2420                      }                                                                                             
2421                      Collections.sort(sBgWorkspaceScreens);                                                        
2422                      // Log to disk                                                                                
2423                      Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);                   
2424                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2425                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2426                                                                                                                    
2427                      LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);                        















2428                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2429                                                                                                                    
2430                      // Update the max item id after we load an old db                                             
2431                      long maxItemId = 0;                                                                           
2432                      // If we're importing we use the old screen order.                                            
2433                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2434                          maxItemId = Math.max(maxItemId, item.id);                                                 
2435                      }                                                                                             
2436                      LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                            
2437                  } else {                                                                                          
2438                      TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);                     
2439                      for (Integer i : orderedScreens.keySet()) {                                                   
2440                          sBgWorkspaceScreens.add(orderedScreens.get(i));                                           
2441                      }                                                                                             
2442                      // Log to disk                                                                                
2443                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2444                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2445                                                                                                                    
2446                      // Remove any empty screens                                                                   
2447                      ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                     
2448                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2449                          long screenId = item.screenId;                                                            
2450                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2451                                  unusedScreens.contains(screenId)) {                                               
2452                              unusedScreens.remove(screenId);                                                       
2453                          }                                                                                         
2454                      }                                                                                             
2455                                                                                                                    
2456                      // If there are any empty screens remove them, and update.                                    
2457                      if (unusedScreens.size() != 0) {                                                              
2458                          // Log to disk                                                                            
2459                          Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                 
2460                                  TextUtils.join(", ", unusedScreens), true);                                       
2461                                                                                                                    
2462                          sBgWorkspaceScreens.removeAll(unusedScreens);                                             
2463                          updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                 
2464                      }                                                                                             
2465                  }                                                                                                 
2466                                                                                                                    
2467                  if (DEBUG_LOADERS) {                                                                              
2468                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2469                      Log.d(TAG, "workspace layout: ");                                                             
2470                      int nScreens = occupied.size();                                                               
2471                      for (int y = 0; y < countY; y++) {                                                            
2472                          String line = "";                                                                         
2473                                                                                                                    
2474                          Iterator<Long> iter = occupied.keySet().iterator();                                       
2475                          while (iter.hasNext()) {                                                                  
2476                              long screenId = iter.next();                                                          


2477                              if (screenId > 0) {                                                                   
2478                                  line += " | ";                                                                    
2479                              }                                                                                     

2480                              for (int x = 0; x < countX; x++) {                                                    
2481                                  ItemInfo[][] screen = occupied.get(screenId);                                     
2482                                  if (x < screen.length && y < screen[x].length) {                                  
2483                                      line += (screen[x][y] != null) ? "#" : ".";                                   
2484                                  } else {                                                                          
2485                                      line += "!";                                                                  
2486                                  }                                                                                 
2487                              }                                                                                     
2488                          }                                                                                         
2489                          Log.d(TAG, "[ " + line + " ]");                                                           
2490                      }                                                                                             
2491                  }                                                                                                 
2492              }                                                                                                     
2493              return loadedOldDb;                                                                                   











2494          }                                                                                                         
2495                                                                                                                    
2496          /** Filters the set of items who are directly or indirectly (via another container) on the                
2497           * specified screen. */                                                                                   
2498          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2499                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2500                  ArrayList<ItemInfo> currentScreenItems,                                                           
2501                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2502              // Purge any null ItemInfos                                                                           
2503              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2504              while (iter.hasNext()) {                                                                              
2505                  ItemInfo i = iter.next();                                                                         
2506                  if (i == null) {                                                                                  
2507                      iter.remove();                                                                                
2508                  }                                                                                                 
2509              }                                                                                                     
2510                                                                                                                    
2511              // Order the set of items by their containers first, this allows use to walk through the              
2512              // list sequentially, build up a list of containers that are in the specified screen,                 
2513              // as well as all items in those containers.                                                          
2514              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2515              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2516                  @Override                                                                                         
2517                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2518                      return (int) (lhs.container - rhs.container);                                                 
2519                  }                                                                                                 
2520              });                                                                                                   
2521              for (ItemInfo info : allWorkspaceItems) {                                                             
2522                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2523                      if (info.screenId == currentScreenId) {                                                       
2524                          currentScreenItems.add(info);                                                             
2525                          itemsOnScreen.add(info.id);                                                               
2526                      } else {                                                                                      
2527                          otherScreenItems.add(info);                                                               
2528                      }                                                                                             
2529                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2530                      currentScreenItems.add(info);                                                                 
2531                      itemsOnScreen.add(info.id);                                                                   
2532                  } else {                                                                                          
2533                      if (itemsOnScreen.contains(info.container)) {                                                 
2534                          currentScreenItems.add(info);                                                             
2535                          itemsOnScreen.add(info.id);                                                               
2536                      } else {                                                                                      
2537                          otherScreenItems.add(info);                                                               
2538                      }                                                                                             
2539                  }                                                                                                 
2540              }                                                                                                     
2541          }                                                                                                         
2542                                                                                                                    
2543          /** Filters the set of widgets which are on the specified screen. */                                      
2544          private void filterCurrentAppWidgets(long currentScreenId,                                                
2545                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
2546                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
2547                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
2548                                                                                                                    
2549              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
2550                  if (widget == null) continue;                                                                     
2551                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
2552                          widget.screenId == currentScreenId) {                                                     
2553                      currentScreenWidgets.add(widget);                                                             
2554                  } else {                                                                                          
2555                      otherScreenWidgets.add(widget);                                                               
2556                  }                                                                                                 
2557              }                                                                                                     
2558          }                                                                                                         
2559                                                                                                                    
2560          /** Filters the set of folders which are on the specified screen. */                                      
2561          private void filterCurrentFolders(long currentScreenId,                                                   
2562                  HashMap<Long, ItemInfo> itemsIdMap,                                                               
2563                  HashMap<Long, FolderInfo> folders,                                                                
2564                  HashMap<Long, FolderInfo> currentScreenFolders,                                                   
2565                  HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
2566                                                                                                                    
2567              for (long id : folders.keySet()) {                                                                    










2568                  ItemInfo info = itemsIdMap.get(id);                                                               
2569                  FolderInfo folder = folders.get(id);                                                              
2570                  if (info == null || folder == null) continue;                                                     
2571                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
2572                          info.screenId == currentScreenId) {                                                       
2573                      currentScreenFolders.put(id, folder);                                                         
2574                  } else {                                                                                          
2575                      otherScreenFolders.put(id, folder);                                                           
2576                  }                                                                                                 
2577              }                                                                                                     
2578          }                                                                                                         
2579                                                                                                                    
2580          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
2581           * right) */                                                                                              
2582          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
2583              final LauncherAppState app = LauncherAppState.getInstance();                                          
2584              final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   

2585              // XXX: review this                                                                                   
2586              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
2587                  @Override                                                                                         
2588                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2589                      int cellCountX = (int) grid.numColumns;                                                       
2590                      int cellCountY = (int) grid.numRows;                                                          


2591                      int screenOffset = cellCountX * cellCountY;                                                   
2592                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
2593                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
2594                              lhs.cellY * cellCountX + lhs.cellX);                                                  
2595                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
2596                              rhs.cellY * cellCountX + rhs.cellX);                                                  
2597                      return (int) (lr - rr);                                                                       
2598                  }                                                                                                 
2599              });                                                                                                   
2600          }                                                                                                         
2601                                                                                                                    
2602          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
2603                  final ArrayList<Long> orderedScreens) {                                                           
2604              final Runnable r = new Runnable() {                                                                   
2605                  @Override                                                                                         
2606                  public void run() {                                                                               
2607                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2608                      if (callbacks != null) {                                                                      
2609                          callbacks.bindScreens(orderedScreens);                                                    
2610                      }                                                                                             
2611                  }                                                                                                 
2612              };                                                                                                    
2613              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     

2614          }                                                                                                         
2615                                                                                                                    
2616          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
2617                  final ArrayList<ItemInfo> workspaceItems,                                                         
2618                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
2619                  final HashMap<Long, FolderInfo> folders,                                                          

2620                  ArrayList<Runnable> deferredBindRunnables) {                                                      
2621                                                                                                                    
2622              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
2623                                                                                                                    
2624              // Bind the workspace items                                                                           
2625              int N = workspaceItems.size();                                                                        
2626              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
2627                  final int start = i;                                                                              
2628                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
2629                  final Runnable r = new Runnable() {                                                               
2630                      @Override                                                                                     
2631                      public void run() {                                                                           
2632                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2633                          if (callbacks != null) {                                                                  
2634                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
2635                                      false);                                                                       
2636                          }                                                                                         
2637                      }                                                                                             
2638                  };                                                                                                
2639                  if (postOnMainThread) {                                                                           
2640                      synchronized (deferredBindRunnables) {                                                        
2641                          deferredBindRunnables.add(r);                                                             
2642                      }                                                                                             
2643                  } else {                                                                                          
2644                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             

2645                  }                                                                                                 
2646              }                                                                                                     
2647                                                                                                                    
2648              // Bind the folders                                                                                   
2649              if (!folders.isEmpty()) {                                                                             
2650                  final Runnable r = new Runnable() {                                                               
2651                      public void run() {                                                                           
2652                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2653                          if (callbacks != null) {                                                                  
2654                              callbacks.bindFolders(folders);                                                       
2655                          }                                                                                         
2656                      }                                                                                             
2657                  };                                                                                                
2658                  if (postOnMainThread) {                                                                           
2659                      synchronized (deferredBindRunnables) {                                                        
2660                          deferredBindRunnables.add(r);                                                             
2661                      }                                                                                             
2662                  } else {                                                                                          
2663                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             

2664                  }                                                                                                 
2665              }                                                                                                     
2666                                                                                                                    
2667              // Bind the widgets, one at a time                                                                    
2668              N = appWidgets.size();                                                                                
2669              for (int i = 0; i < N; i++) {                                                                         
2670                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
2671                  final Runnable r = new Runnable() {                                                               
2672                      public void run() {                                                                           
2673                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2674                          if (callbacks != null) {                                                                  
2675                              callbacks.bindAppWidget(widget);                                                      
2676                          }                                                                                         
2677                      }                                                                                             
2678                  };                                                                                                
2679                  if (postOnMainThread) {                                                                           
2680                      deferredBindRunnables.add(r);                                                                 
2681                  } else {                                                                                          
2682                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             

2683                  }                                                                                                 
2684              }                                                                                                     
2685          }                                                                                                         
2686                                                                                                                    
2687          /**                                                                                                       
2688           * Binds all loaded data to actual views on the main thread.                                              
2689           */                                                                                                       
2690          private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {                        

2691              final long t = SystemClock.uptimeMillis();                                                            
2692              Runnable r;                                                                                           
2693                                                                                                                    
2694              // Don't use these two variables in any of the callback runnables.                                    
2695              // Otherwise we hold a reference to them.                                                             
2696              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2697              if (oldCallbacks == null) {                                                                           
2698                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2699                  Log.w(TAG, "LoaderTask running with no launcher");                                                
2700                  return;                                                                                           
2701              }                                                                                                     
2702                                                                                                                    
2703              // Save a copy of all the bg-thread collections                                                       
2704              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
2705              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
2706                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2707              HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
2708              HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
2709              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             




2710              synchronized (sBgLock) {                                                                              
2711                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
2712                  appWidgets.addAll(sBgAppWidgets);                                                                 
2713                  folders.putAll(sBgFolders);                                                                       
2714                  itemsIdMap.putAll(sBgItemsIdMap);                                                                 
2715                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     



2716              }                                                                                                     
2717                                                                                                                    
2718              final boolean isLoadingSynchronously =                                                                
2719                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
2720              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
2721                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
2722              if (currScreen >= orderedScreenIds.size()) {                                                          
2723                  // There may be no workspace screens (just hotseat items and an empty page).                      
2724                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
2725              }                                                                                                     
2726              final int currentScreen = currScreen;                                                                 
2727              final long currentScreenId = currentScreen < 0                                                        
2728                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
2729                                                                                                                    
2730              // Load all the items that are on the current page first (and in the process, unbind                  
2731              // all the existing workspace items before we call startBinding() below.                              
2732              unbindWorkspaceItemsOnMainThread();                                                                   
2733                                                                                                                    
2734              // Separate the items that are on the current screen, and all the other remaining items               
2735              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
2736              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
2737              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
2738                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2739              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
2740                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2741              HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
2742              HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             


2743                                                                                                                    
2744              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
2745                      otherWorkspaceItems);                                                                         
2746              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
2747                      otherAppWidgets);                                                                             
2748              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
2749                      otherFolders);                                                                                
2750              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
2751              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
2752                                                                                                                    
2753              // Tell the workspace that we're about to start binding items                                         
2754              r = new Runnable() {                                                                                  
2755                  public void run() {                                                                               
2756                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2757                      if (callbacks != null) {                                                                      
2758                          callbacks.startBinding();                                                                 
2759                      }                                                                                             
2760                  }                                                                                                 
2761              };                                                                                                    
2762              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     

2763                                                                                                                    
2764              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
2765                                                                                                                    
2766              // Load items on the current page                                                                     
2767              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
2768                      currentFolders, null);                                                                        
2769              if (isLoadingSynchronously) {                                                                         
2770                  r = new Runnable() {                                                                              
2771                      public void run() {                                                                           
2772                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2773                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
2774                              callbacks.onPageBoundSynchronously(currentScreen);                                    
2775                          }                                                                                         
2776                      }                                                                                             
2777                  };                                                                                                
2778                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 

2779              }                                                                                                     
2780                                                                                                                    
2781              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
2782              // work until after the first render)                                                                 
2783              synchronized (mDeferredBindRunnables) {                                                               
2784                  mDeferredBindRunnables.clear();                                                                   
2785              }                                                                                                     
2786              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
2787                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
2788                                                                                                                    
2789              // Tell the workspace that we're done binding items                                                   
2790              r = new Runnable() {                                                                                  
2791                  public void run() {                                                                               
2792                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2793                      if (callbacks != null) {                                                                      
2794                          callbacks.finishBindingItems(isUpgradePath);                                              

2795                      }                                                                                             
2796                                                                                                                    
2797                      // If we're profiling, ensure this is the last thing in the queue.                            
2798                      if (DEBUG_LOADERS) {                                                                          
2799                          Log.d(TAG, "bound workspace in "                                                          
2800                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
2801                      }                                                                                             
2802                                                                                                                    
2803                      mIsLoadingAndBindingWorkspace = false;                                                        
2804                  }                                                                                                 
2805              };                                                                                                    
2806              if (isLoadingSynchronously) {                                                                         
2807                  synchronized (mDeferredBindRunnables) {                                                           
2808                      mDeferredBindRunnables.add(r);                                                                
2809                  }                                                                                                 
2810              } else {                                                                                              
2811                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 

2812              }                                                                                                     
2813          }                                                                                                         
2814                                                                                                                    
2815          private void loadAndBindAllApps() {                                                                       
2816              if (DEBUG_LOADERS) {                                                                                  
2817                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
2818              }                                                                                                     
2819              if (!mAllAppsLoaded) {                                                                                
2820                  loadAllApps();                                                                                    
2821                  synchronized (LoaderTask.this) {                                                                  
2822                      if (mStopped) {                                                                               
2823                          return;                                                                                   
2824                      }                                                                                             






2825                      mAllAppsLoaded = true;                                                                        
2826                  }                                                                                                 
2827              } else {                                                                                              
2828                  onlyBindAllApps();                                                                                
2829              }                                                                                                     





















2830          }                                                                                                         
2831                                                                                                                    
2832          private void onlyBindAllApps() {                                                                          
2833              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2834              if (oldCallbacks == null) {                                                                           
2835                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2836                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
2837                  return;                                                                                           
2838              }                                                                                                     
2839                                                                                                                    
2840              // shallow copy                                                                                       
2841              @SuppressWarnings("unchecked")                                                                        
2842              final ArrayList<AppInfo> list                                                                         
2843                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           

2844              Runnable r = new Runnable() {                                                                         
2845                  public void run() {                                                                               
2846                      final long t = SystemClock.uptimeMillis();                                                    
2847                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2848                      if (callbacks != null) {                                                                      
2849                          callbacks.bindAllApplications(list);                                                      

2850                      }                                                                                             
2851                      if (DEBUG_LOADERS) {                                                                          
2852                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
2853                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
2854                      }                                                                                             
2855                  }                                                                                                 
2856              };                                                                                                    
2857              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
2858              if (isRunningOnMainThread) {                                                                          
2859                  r.run();                                                                                          
2860              } else {                                                                                              
2861                  mHandler.post(r);                                                                                 
2862              }                                                                                                     
2863          }                                                                                                         
2864                                                                                                                    
2865          private void loadAllApps() {                                                                              
2866              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2867                                                                                                                    
2868              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2869              if (oldCallbacks == null) {                                                                           
2870                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2871                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
2872                  return;                                                                                           
2873              }                                                                                                     
2874                                                                                                                    
2875              final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
2876              mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
2877                                                                                                                    
2878              final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                               
2879                                                                                                                    
2880              // Clear the list of apps                                                                             
2881              mBgAllAppsList.clear();                                                                               
2882              SharedPreferences prefs = mContext.getSharedPreferences(                                              
2883                      LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                            
2884              for (UserHandleCompat user : profiles) {                                                              
2885                  // Query for the set of apps                                                                      
2886                  final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                              
2887                  List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);                

2888                  if (DEBUG_LOADERS) {                                                                              
2889                      Log.d(TAG, "getActivityList took "                                                            
2890                              + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);                      
2891                      Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);                  
2892                  }                                                                                                 
2893                  // Fail if we don't have any apps                                                                 
2894                  // TODO: Fix this. Only fail for the current user.                                                
2895                  if (apps == null || apps.isEmpty()) {                                                             
2896                      return;                                                                                       
2897                  }                                                                                                 
2898                  // Sort the applications by name                                                                  
2899                  final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                             
2900                  Collections.sort(apps,                                                                            
2901                          new LauncherModel.ShortcutNameComparator(mLabelCache));                                   
2902                  if (DEBUG_LOADERS) {                                                                              
2903                      Log.d(TAG, "sort took "                                                                       
2904                              + (SystemClock.uptimeMillis()-sortTime) + "ms");                                      
2905                  }                                                                                                 
2906                                                                                                                    
2907                  // Create the ApplicationInfos                                                                    
2908                  for (int i = 0; i < apps.size(); i++) {                                                           
2909                      LauncherActivityInfoCompat app = apps.get(i);                                                 
2910                      // This builds the icon bitmaps.                                                              
2911                      mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));                
2912                  }                                                                                                 
2913                                                                                                                    
2914                  if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {             
2915                      // Add shortcuts for packages which were installed while launcher was dead.                   
2916                      String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                       
2917                              + mUserManager.getSerialNumberForUser(user);                                          
2918                      Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);       
2919                      HashSet<String> newPackageSet = new HashSet<String>();                                        
2920                                                                                                                    
2921                      for (LauncherActivityInfoCompat info : apps) {                                                
2922                          String packageName = info.getComponentName().getPackageName();                            
2923                          if (!packagesAdded.contains(packageName)                                                  
2924                                  && !newPackageSet.contains(packageName)) {                                        
2925                              InstallShortcutReceiver.queueInstallShortcut(info, mContext);                         










2926                          }                                                                                         
2927                          newPackageSet.add(packageName);                                                           
2928                      }                                                                                             
2929                                                                                                                    
2930                      prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                           

2931                  }                                                                                                 
2932              }                                                                                                     
2933              // Huh? Shouldn't this be inside the Runnable below?                                                  
2934              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
2935              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
2936                                                                                                                    
2937              // Post callback on main thread                                                                       
2938              mHandler.post(new Runnable() {                                                                        
2939                  public void run() {                                                                               

2940                      final long bindTime = SystemClock.uptimeMillis();                                             
2941                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2942                      if (callbacks != null) {                                                                      
2943                          callbacks.bindAllApplications(added);                                                     
2944                          if (DEBUG_LOADERS) {                                                                      
2945                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
2946                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
2947                          }                                                                                         
2948                      } else {                                                                                      
2949                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
2950                      }                                                                                             
2951                  }                                                                                                 
2952              });                                                                                                   
2953                                                                                                                    





2954              if (DEBUG_LOADERS) {                                                                                  
2955                  Log.d(TAG, "Icons processed in "                                                                  
2956                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
2957              }                                                                                                     
2958          }                                                                                                         
2959                                                                                                                    
2960          public void dumpState() {                                                                                 
2961              synchronized (sBgLock) {                                                                              
2962                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
2963                  Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
2964                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
2965                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
2966                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
2967              }                                                                                                     
2968          }                                                                                                         
2969      }                                                                                                             
2970                                                                                                                    























































2971      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
2972          sWorker.post(task);                                                                                       
2973      }                                                                                                             
2974                                                                                                                    
2975      private class AppsAvailabilityCheck extends BroadcastReceiver {                                               

2976                                                                                                                    
2977          @Override                                                                                                 
2978          public void onReceive(Context context, Intent intent) {                                                   
2979              synchronized (sBgLock) {                                                                              
2980                  final LauncherAppsCompat launcherApps = LauncherAppsCompat                                        
2981                          .getInstance(mApp.getContext());                                                          
2982                  final PackageManager manager = context.getPackageManager();                                       
2983                  final ArrayList<String> packagesRemoved = new ArrayList<String>();                                
2984                  final ArrayList<String> packagesUnavailable = new ArrayList<String>();                            
2985                  for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {              
2986                      UserHandleCompat user = entry.getKey();                                                       
2987                      packagesRemoved.clear();                                                                      
2988                      packagesUnavailable.clear();                                                                  
2989                      for (String pkg : entry.getValue()) {                                                         
2990                          if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                                
2991                              boolean packageOnSdcard = launcherApps.isAppEnabled(                                  
2992                                      manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);                       
2993                              if (packageOnSdcard) {                                                                
2994                                  Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);               
2995                                  packagesUnavailable.add(pkg);                                                     
2996                              } else {                                                                              
2997                                  Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);                      
2998                                  packagesRemoved.add(pkg);                                                         
2999                              }                                                                                     
3000                          }                                                                                         
3001                      }                                                                                             
3002                      if (!packagesRemoved.isEmpty()) {                                                             
3003                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,                
3004                                  packagesRemoved.toArray(new String[packagesRemoved.size()]), user));              
3005                      }                                                                                             
3006                      if (!packagesUnavailable.isEmpty()) {                                                         
3007                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,           
3008                                  packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));      
3009                      }                                                                                             
3010                  }                                                                                                 
3011                  sPendingPackages.clear();                                                                         
3012              }                                                                                                     
3013          }                                                                                                         
3014      }                                                                                                             
3015                                                                                                                    
3016      private class PackageUpdatedTask implements Runnable {                                                        
3017          int mOp;                                                                                                  
3018          String[] mPackages;                                                                                       
3019          UserHandleCompat mUser;                                                                                   
3020                                                                                                                    
3021          public static final int OP_NONE = 0;                                                                      
3022          public static final int OP_ADD = 1;                                                                       
3023          public static final int OP_UPDATE = 2;                                                                    
3024          public static final int OP_REMOVE = 3; // uninstlled                                                      
3025          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
3026                                                                                                                    
3027                                                                                                                    
3028          public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                             
3029              mOp = op;                                                                                             
3030              mPackages = packages;                                                                                 
3031              mUser = user;                                                                                         
3032          }                                                                                                         
3033                                                                                                                    
3034          public void run() {                                                                                       




3035              final Context context = mApp.getContext();                                                            
3036                                                                                                                    
3037              final String[] packages = mPackages;                                                                  
3038              final int N = packages.length;                                                                        
3039              switch (mOp) {                                                                                        
3040                  case OP_ADD:                                                                                      

3041                      for (int i=0; i<N; i++) {                                                                     
3042                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
3043                          mIconCache.remove(packages[i], mUser);                                                    

3044                          mBgAllAppsList.addPackage(context, packages[i], mUser);                                   
3045                      }                                                                                             
3046                                                                                                                    
3047                      // Auto add shortcuts for added packages.                                                     
3048                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3049                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3050                          SharedPreferences prefs = context.getSharedPreferences(                                   
3051                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3052                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3053                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3054                          Set<String> shortcutSet = new HashSet<String>(                                            
3055                                  prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));                       
3056                                                                                                                    
3057                          for (int i=0; i<N; i++) {                                                                 
3058                              if (!shortcutSet.contains(packages[i])) {                                             
3059                                  shortcutSet.add(packages[i]);                                                     
3060                                  List<LauncherActivityInfoCompat> activities =                                     
3061                                          mLauncherApps.getActivityList(packages[i], mUser);                        
3062                                  if (activities != null && !activities.isEmpty()) {                                
3063                                      InstallShortcutReceiver.queueInstallShortcut(                                 
3064                                              activities.get(0), context);                                          
3065                                  }                                                                                 
3066                              }                                                                                     
3067                          }                                                                                         
3068                                                                                                                    
3069                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         



3070                      }                                                                                             
3071                      break;                                                                                        

3072                  case OP_UPDATE:                                                                                   
3073                      for (int i=0; i<N; i++) {                                                                     
3074                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               

3075                          mBgAllAppsList.updatePackage(context, packages[i], mUser);                                
3076                          WidgetPreviewLoader.removePackageFromDb(                                                  
3077                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     

3078                      }                                                                                             
3079                      break;                                                                                        
3080                  case OP_REMOVE:                                                                                   
3081                      // Remove the packageName for the set of auto-installed shortcuts. This                       
3082                      // will ensure that the shortcut when the app is installed again.                             
3083                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3084                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3085                          SharedPreferences prefs = context.getSharedPreferences(                                   
3086                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3087                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3088                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3089                          HashSet<String> shortcutSet = new HashSet<String>(                                        
3090                                  prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));                      
3091                          shortcutSet.removeAll(Arrays.asList(mPackages));                                          
3092                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3093                      }                                                                                             
3094                      // Fall through                                                                               
3095                  case OP_UNAVAILABLE:                                                                              
3096                      boolean clearCache = mOp == OP_REMOVE;                                                        





3097                      for (int i=0; i<N; i++) {                                                                     
3098                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3099                          mBgAllAppsList.removePackage(packages[i], mUser, clearCache);                             
3100                          WidgetPreviewLoader.removePackageFromDb(                                                  
3101                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     









3102                      }                                                                                             
3103                      break;                                                                                        
3104              }                                                                                                     
3105                                                                                                                    
3106              ArrayList<AppInfo> added = null;                                                                      
3107              ArrayList<AppInfo> modified = null;                                                                   
3108              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
3109                                                                                                                    
3110              if (mBgAllAppsList.added.size() > 0) {                                                                
3111                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
3112                  mBgAllAppsList.added.clear();                                                                     
3113              }                                                                                                     
3114              if (mBgAllAppsList.modified.size() > 0) {                                                             
3115                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
3116                  mBgAllAppsList.modified.clear();                                                                  
3117              }                                                                                                     
3118              if (mBgAllAppsList.removed.size() > 0) {                                                              
3119                  removedApps.addAll(mBgAllAppsList.removed);                                                       
3120                  mBgAllAppsList.removed.clear();                                                                   
3121              }                                                                                                     
3122                                                                                                                    
3123              final Callbacks callbacks = getCallback();                                                            
3124              if (callbacks == null) {                                                                              
3125                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
3126                  return;                                                                                           
3127              }                                                                                                     
3128                                                                                                                    
3129              final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                            
3130                      new HashMap<ComponentName, AppInfo>();                                                        
3131                                                                                                                    
3132              if (added != null) {                                                                                  
3133                  // Ensure that we add all the workspace applications to the db                                    
3134                  if (LauncherAppState.isDisableAllApps()) {                                                        
3135                      final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
3136                      addAndBindAddedWorkspaceApps(context, addedInfos);                                            
3137                  } else {                                                                                          
3138                      addAppsToAllApps(context, added);                                                             
3139                  }                                                                                                 

3140                  for (AppInfo ai : added) {                                                                        
3141                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3142                  }                                                                                                 
3143              }                                                                                                     
3144                                                                                                                    
3145              if (modified != null) {                                                                               
3146                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
3147                  for (AppInfo ai : modified) {                                                                     
3148                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3149                  }                                                                                                 
3150                                                                                                                    
3151                  mHandler.post(new Runnable() {                                                                    
3152                      public void run() {                                                                           
3153                          Callbacks cb = getCallback();                                                             
3154                          if (callbacks == cb && cb != null) {                                                      
3155                              callbacks.bindAppsUpdated(modifiedFinal);                                             
3156                          }                                                                                         
3157                      }                                                                                             
3158                  });                                                                                               
3159              }                                                                                                     
3160                                                                                                                    
3161              // Update shortcut infos                                                                              
3162              if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                              
3163                  final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();                   
3164                  final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();                   
3165                  final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();          
3166                                                                                                                    
3167                  HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));                        
3168                  synchronized (sBgLock) {                                                                          
3169                      for (ItemInfo info : sBgItemsIdMap.values()) {                                                

3170                          if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                            
3171                              ShortcutInfo si = (ShortcutInfo) info;                                                
3172                              boolean infoUpdated = false;                                                          
3173                              boolean shortcutUpdated = false;                                                      
3174                                                                                                                    
3175                              // Update shortcuts which use iconResource.                                           
3176                              if ((si.iconResource != null)                                                         
3177                                      && packageSet.contains(si.iconResource.packageName)) {                        
3178                                  Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,             
3179                                          si.iconResource.resourceName, mIconCache, context);                       



3180                                  if (icon != null) {                                                               
3181                                      si.setIcon(icon);                                                             
3182                                      si.usingFallbackIcon = false;                                                 
3183                                      infoUpdated = true;                                                           
3184                                  }                                                                                 
3185                              }                                                                                     
3186                                                                                                                    
3187                              ComponentName cn = si.getTargetComponent();                                           
3188                              if (cn != null && packageSet.contains(cn.getPackageName())) {                         
3189                                  AppInfo appInfo = addedOrUpdatedApps.get(cn);                                     
3190                                                                                                                    
3191                                  if (si.isPromise()) {                                                             
3192                                      mIconCache.deletePreloadedIcon(cn, mUser);                                    
3193                                      if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                    
3194                                          // Auto install icon                                                      
3195                                          PackageManager pm = context.getPackageManager();                          
3196                                          ResolveInfo matched = pm.resolveActivity(                                 
3197                                                  new Intent(Intent.ACTION_MAIN)                                    
3198                                                  .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),          
3199                                                  PackageManager.MATCH_DEFAULT_ONLY);                               
3200                                          if (matched == null) {                                                    
3201                                              // Try to find the best match activity.                               
3202                                              Intent intent = pm.getLaunchIntentForPackage(                         
3203                                                      cn.getPackageName());                                         
3204                                              if (intent != null) {                                                 
3205                                                  cn = intent.getComponent();                                       
3206                                                  appInfo = addedOrUpdatedApps.get(cn);                             
3207                                              }                                                                     
3208                                                                                                                    
3209                                              if ((intent == null) || (appInfo == null)) {                          
3210                                                  removedShortcuts.add(si);                                         
3211                                                  continue;                                                         
3212                                              }                                                                     
3213                                              si.promisedIntent = intent;                                           
3214                                          }                                                                         
3215                                      }                                                                             
3216                                                                                                                    
3217                                      // Restore the shortcut.                                                      




3218                                      si.intent = si.promisedIntent;                                                
3219                                      si.promisedIntent = null;                                                     
3220                                      si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                                 
3221                                              & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                  
3222                                              & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                          
3223                                                                                                                    

3224                                      infoUpdated = true;                                                           
3225                                      si.updateIcon(mIconCache);                                                    
3226                                  }                                                                                 
3227                                                                                                                    
3228                                  if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())           
3229                                          && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {     
3230                                      si.updateIcon(mIconCache);                                                    
3231                                      si.title = appInfo.title.toString();                                          

3232                                      si.contentDescription = appInfo.contentDescription;                           
3233                                      infoUpdated = true;                                                           
3234                                  }                                                                                 
3235                                                                                                                    
3236                                  if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {            
3237                                      // Since package was just updated, the target must be available now.          
3238                                      si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                   
3239                                      shortcutUpdated = true;                                                       
3240                                  }                                                                                 
3241                              }                                                                                     
3242                                                                                                                    
3243                              if (infoUpdated || shortcutUpdated) {                                                 
3244                                  updatedShortcuts.add(si);                                                         
3245                              }                                                                                     
3246                              if (infoUpdated) {                                                                    
3247                                  updateItemInDatabase(context, si);                                                
3248                              }                                                                                     
3249                          } else if (info instanceof LauncherAppWidgetInfo) {                                       
3250                              LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                      
3251                              if (mUser.equals(widgetInfo.user)                                                     
3252                                      && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)   
3253                                      && packageSet.contains(widgetInfo.providerName.getPackageName())) {           
3254                                  widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;       
3255                                  widgets.add(widgetInfo);                                                          
3256                                  updateItemInDatabase(context, widgetInfo);                                        
3257                              }                                                                                     
3258                          }                                                                                         
3259                      }                                                                                             
3260                  }                                                                                                 
3261                                                                                                                    
3262                  if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                                 
3263                      mHandler.post(new Runnable() {                                                                
3264                                                                                                                    
3265                          public void run() {                                                                       
3266                              Callbacks cb = getCallback();                                                         
3267                              if (callbacks == cb && cb != null) {                                                  
3268                                  callbacks.bindShortcutsChanged(                                                   
3269                                          updatedShortcuts, removedShortcuts, mUser);                               
3270                              }                                                                                     
3271                          }                                                                                         
3272                      });                                                                                           
3273                      if (!removedShortcuts.isEmpty()) {                                                            
3274                          deleteItemsFromDatabase(context, removedShortcuts);                                       
3275                      }                                                                                             
3276                  }                                                                                                 
3277                  if (!widgets.isEmpty()) {                                                                         
3278                      mHandler.post(new Runnable() {                                                                
3279                          public void run() {                                                                       
3280                              Callbacks cb = getCallback();                                                         
3281                              if (callbacks == cb && cb != null) {                                                  
3282                                  callbacks.bindWidgetsRestored(widgets);                                           
3283                              }                                                                                     
3284                          }                                                                                         
3285                      });                                                                                           
3286                  }                                                                                                 
3287              }                                                                                                     
3288                                                                                                                    
3289              final ArrayList<String> removedPackageNames =                                                         
3290                      new ArrayList<String>();                                                                      
3291              if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                                      
3292                  // Mark all packages in the broadcast to be removed                                               
3293                  removedPackageNames.addAll(Arrays.asList(packages));                                              
3294              } else if (mOp == OP_UPDATE) {                                                                        
3295                  // Mark disabled packages in the broadcast to be removed                                          
3296                  for (int i=0; i<N; i++) {                                                                         
3297                      if (isPackageDisabled(context, packages[i], mUser)) {                                         
3298                          removedPackageNames.add(packages[i]);                                                     
3299                      }                                                                                             
3300                  }                                                                                                 
3301              }                                                                                                     
3302                                                                                                                    
3303              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
3304                  final int removeReason;                                                                           
3305                  if (mOp == OP_UNAVAILABLE) {                                                                      
3306                      removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                                      
3307                  } else {                                                                                          
3308                      // Remove all the components associated with this package                                     
3309                      for (String pn : removedPackageNames) {                                                       
3310                          deletePackageFromDatabase(context, pn, mUser);                                            
3311                      }                                                                                             
3312                      // Remove all the specific components                                                         
3313                      for (AppInfo a : removedApps) {                                                               
3314                          ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);          
3315                          deleteItemsFromDatabase(context, infos);                                                  
3316                      }                                                                                             
3317                      removeReason = 0;                                                                             
3318                  }                                                                                                 
3319                                                                                                                    
3320                  // Remove any queued items from the install queue                                                 
3321                  InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);              
3322                  // Call the components-removed callback                                                           
3323                  mHandler.post(new Runnable() {                                                                    
3324                      public void run() {                                                                           
3325                          Callbacks cb = getCallback();                                                             
3326                          if (callbacks == cb && cb != null) {                                                      
3327                              callbacks.bindComponentsRemoved(                                                      
3328                                      removedPackageNames, removedApps, mUser, removeReason);                       
3329                          }                                                                                         
3330                      }                                                                                             
3331                  });                                                                                               
3332              }                                                                                                     
3333              if (Build.VERSION.SDK_INT < 17) {                                                                     
3334                  loadAndBindWidgetsAndShortcuts(context, callbacks);                                               
3335              }                                                                                                     




3336              // Write all the logs to disk                                                                         
3337              mHandler.post(new Runnable() {                                                                        
3338                  public void run() {                                                                               
3339                      Callbacks cb = getCallback();                                                                 
3340                      if (callbacks == cb && cb != null) {                                                          
3341                          callbacks.dumpLogsToLocalData();                                                          
3342                      }                                                                                             
3343                  }                                                                                                 
3344              });                                                                                                   
3345          }                                                                                                         
3346      }                                                                                                             
3347                                                                                                                    
3348      public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context,                         
3349              boolean refresh) {                                                                                    
3350          ArrayList<LauncherAppWidgetProviderInfo> results =                                                        
3351                  new ArrayList<LauncherAppWidgetProviderInfo>();                                                   
3352          try {                                                                                                     
3353              synchronized (sBgLock) {                                                                              
3354                  if (sBgWidgetProviders == null || refresh) {                                                      
3355                      HashMap<ComponentKey, LauncherAppWidgetProviderInfo> tmpWidgetProviders                       
3356                              = new HashMap<>();                                                                    
3357                      AppWidgetManagerCompat wm = AppWidgetManagerCompat.getInstance(context);                      
3358                      LauncherAppWidgetProviderInfo info;                                                           
3359                                                                                                                    
3360                      List<AppWidgetProviderInfo> widgets = wm.getAllProviders();                                   
3361                      for (AppWidgetProviderInfo pInfo : widgets) {                                                 
3362                          info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                    
3363                          UserHandleCompat user = wm.getUser(info);                                                 
3364                          tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);                      
3365                      }                                                                                             
3366                                                                                                                    
3367                      Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();          
3368                      for (CustomAppWidget widget : customWidgets) {                                                
3369                          info = new LauncherAppWidgetProviderInfo(context, widget);                                
3370                          UserHandleCompat user = wm.getUser(info);                                                 
3371                          tmpWidgetProviders.put(new ComponentKey(info.provider, user), info);                      
3372                      }                                                                                             
3373                      // Replace the global list at the very end, so that if there is an exception,                 
3374                      // previously loaded provider list is used.                                                   
3375                      sBgWidgetProviders = tmpWidgetProviders;                                                      
3376                  }                                                                                                 
3377                  results.addAll(sBgWidgetProviders.values());                                                      
3378                  return results;                                                                                   
3379              }                                                                                                     
3380          } catch (Exception e) {                                                                                   
3381              if (e.getCause() instanceof TransactionTooLargeException) {                                           
3382                  // the returned value may be incomplete and will not be refreshed until the next                  
3383                  // time Launcher starts.                                                                          
3384                  // TODO: after figuring out a repro step, introduce a dirty bit to check when                     
3385                  // onResume is called to refresh the widget provider list.                                        
3386                  synchronized (sBgLock) {                                                                          
3387                      if (sBgWidgetProviders != null) {                                                             
3388                          results.addAll(sBgWidgetProviders.values());                                              
3389                      }                                                                                             
3390                      return results;                                                                               
3391                  }                                                                                                 
3392              } else {                                                                                              
3393                  throw e;                                                                                          
3394              }                                                                                                     
3395          }                                                                                                         
3396      }                                                                                                             
3397                                                                                                                    
3398      public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name,                  
3399              UserHandleCompat user) {                                                                              
3400          synchronized (sBgLock) {                                                                                  
3401              if (sBgWidgetProviders == null) {                                                                     
3402                  getWidgetProviders(ctx, false /* refresh */);                                                     
3403              }                                                                                                     
3404              return sBgWidgetProviders.get(new ComponentKey(name, user));                                          
3405          }                                                                                                         
3406      }                                                                                                             
3407                                                                                                                    
3408      public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks) {                
3409          runOnWorkerThread(new Runnable(){                                                                         




3410              @Override                                                                                             
3411              public void run() {                                                                                   
3412                  final ArrayList<Object> list =                                                                    
3413                          getSortedWidgetsAndShortcuts(context, true /* refresh */);                                



3414                  mHandler.post(new Runnable() {                                                                    
3415                      @Override                                                                                     
3416                      public void run() {                                                                           
3417                          Callbacks cb = getCallback();                                                             
3418                          if (callbacks == cb && cb != null) {                                                      
3419                              callbacks.bindPackagesUpdated(list);                                                  

3420                          }                                                                                         
3421                      }                                                                                             
3422                  });                                                                                               



3423              }                                                                                                     
3424          });                                                                                                       
3425      }                                                                                                             
3426                                                                                                                    
3427      // Returns a list of ResolveInfos/AppWidgetInfos in sorted order                                              
3428      public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context, boolean refresh) {              






3429          PackageManager packageManager = context.getPackageManager();                                              
3430          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
3431          widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh));                                         
3432          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
3433          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
3434          Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));                      
3435          return widgetsAndShortcuts;                                                                               
3436      }                                                                                                             
3437                                                                                                                    
3438      private static boolean isPackageDisabled(Context context, String packageName,                                 




3439              UserHandleCompat user) {                                                                              
3440          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3441          return !launcherApps.isPackageEnabledForProfile(packageName, user);                                       
3442      }                                                                                                             
3443                                                                                                                    
3444      public static boolean isValidPackageActivity(Context context, ComponentName cn,                               
3445              UserHandleCompat user) {                                                                              
3446          if (cn == null) {                                                                                         
3447              return false;                                                                                         
3448          }                                                                                                         
3449          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3450          if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                                
3451              return false;                                                                                         
3452          }                                                                                                         
3453          return launcherApps.isActivityEnabledForProfile(cn, user);                                                
3454      }                                                                                                             
3455                                                                                                                    
3456      public static boolean isValidPackage(Context context, String packageName,                                     
3457              UserHandleCompat user) {                                                                              
3458          if (packageName == null) {                                                                                
3459              return false;                                                                                         
3460          }                                                                                                         
3461          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3462          return launcherApps.isPackageEnabledForProfile(packageName, user);                                        
3463      }                                                                                                             
3464                                                                                                                    
3465      /**                                                                                                           
3466       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
3467       * to a package that is not yet installed on the system.                                                      
3468       */                                                                                                           
3469      public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                         
3470              int promiseType) {                                                                                    


3471          final ShortcutInfo info = new ShortcutInfo();                                                             
3472          info.user = UserHandleCompat.myUserHandle();                                                              
3473          mIconCache.getTitleAndIcon(info, intent, info.user, true);                                                








3474                                                                                                                    
3475          if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                               
3476              String title = (cursor != null) ? cursor.getString(titleIndex) : null;                                

3477              if (!TextUtils.isEmpty(title)) {                                                                      
3478                  info.title = title;                                                                               
3479              }                                                                                                     
3480              info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                                        


3481          } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                                     
3482              if (TextUtils.isEmpty(info.title)) {                                                                  
3483                  info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                                
3484              }                                                                                                     
3485              info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                                      


3486          } else {                                                                                                  
3487              throw new InvalidParameterException("Invalid restoreType " + promiseType);                            
3488          }                                                                                                         
3489                                                                                                                    
3490          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3491                  info.title.toString(), info.user);                                                                
3492          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            


3493          info.promisedIntent = intent;                                                                             

3494          return info;                                                                                              
3495      }                                                                                                             
3496                                                                                                                    
3497      /**                                                                                                           
3498       * Make an Intent object for a restored application or shortcut item that points                              
3499       * to the market page for the item.                                                                           
3500       */                                                                                                           
3501      private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              

3502          ComponentName componentName = intent.getComponent();                                                      
3503          return getMarketIntent(componentName.getPackageName());                                                   
3504      }                                                                                                             
3505                                                                                                                    
3506      static Intent getMarketIntent(String packageName) {                                                           
3507          return new Intent(Intent.ACTION_VIEW)                                                                     
3508              .setData(new Uri.Builder()                                                                            
3509                  .scheme("market")                                                                                 
3510                  .authority("details")                                                                             
3511                  .appendQueryParameter("id", packageName)                                                          
3512                  .build());                                                                                        
3513      }                                                                                                             
3514                                                                                                                    
3515      /**                                                                                                           
3516       * This is called from the code that adds shortcuts from the intent receiver.  This                           
3517       * doesn't have a Cursor, but                                                                                 
3518       */                                                                                                           
3519      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
3520              UserHandleCompat user, Context context) {                                                             
3521          return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);                        
3522      }                                                                                                             
3523                                                                                                                    
3524      /**                                                                                                           
3525       * Make an ShortcutInfo object for a shortcut that is an application.                                         
3526       *                                                                                                            
3527       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
3528       */                                                                                                           
3529      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    

3530              UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,                      
3531              HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {                               

3532          if (user == null) {                                                                                       
3533              Log.d(TAG, "Null user found in getShortcutInfo");                                                     
3534              return null;                                                                                          
3535          }                                                                                                         
3536                                                                                                                    
3537          ComponentName componentName = intent.getComponent();                                                      
3538          if (componentName == null) {                                                                              
3539              Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                           
3540              return null;                                                                                          
3541          }                                                                                                         
3542                                                                                                                    
3543          Intent newIntent = new Intent(intent.getAction(), null);                                                  
3544          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
3545          newIntent.setComponent(componentName);                                                                    
3546          LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                          
3547          if ((lai == null) && !allowMissingTarget) {                                                               
3548              Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                            
3549              return null;                                                                                          
3550          }                                                                                                         
3551                                                                                                                    
3552          final ShortcutInfo info = new ShortcutInfo();                                                             
3553                                                                                                                    
3554          // the resource -- This may implicitly give us back the fallback icon,                                    
3555          // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
3556          // to avoid saving lots of copies of that in the database, and most apps                                  
3557          // have icons anyway.                                                                                     
3558          Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);                                         
3559                                                                                                                    
3560          // the db                                                                                                 
3561          if (icon == null) {                                                                                       
3562              if (c != null) {                                                                                      
3563                  icon = getIconFromCursor(c, iconIndex, context);                                                  
3564              }                                                                                                     
3565          }                                                                                                         
3566          // the fallback icon                                                                                      
3567          if (icon == null) {                                                                                       
3568              icon = mIconCache.getDefaultIcon(user);                                                               
3569              info.usingFallbackIcon = true;                                                                        
3570          }                                                                                                         
3571          info.setIcon(icon);                                                                                       
3572                                                                                                                    
3573          // From the cache.                                                                                        
3574          if (labelCache != null) {                                                                                 
3575              info.title = labelCache.get(componentName);                                                           
3576          }                                                                                                         
3577                                                                                                                    
3578          // from the resource                                                                                      
3579          if (info.title == null && lai != null) {                                                                  
3580              info.title = lai.getLabel();                                                                          
3581              if (labelCache != null) {                                                                             
3582                  labelCache.put(componentName, info.title);                                                        
3583              }                                                                                                     
3584          }                                                                                                         






3585          // from the db                                                                                            
3586          if (info.title == null) {                                                                                 
3587              if (c != null) {                                                                                      
3588                  info.title =  c.getString(titleIndex);                                                            
3589              }                                                                                                     
3590          }                                                                                                         




3591          // fall back to the class name of the activity                                                            
3592          if (info.title == null) {                                                                                 
3593              info.title = componentName.getClassName();                                                            
3594          }                                                                                                         

3595          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
3596          info.user = user;                                                                                         
3597          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3598                  info.title.toString(), info.user);                                                                




3599          return info;                                                                                              
3600      }                                                                                                             
3601                                                                                                                    
3602      static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        

3603              ItemInfoFilter f) {                                                                                   
3604          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
3605          for (ItemInfo i : infos) {                                                                                
3606              if (i instanceof ShortcutInfo) {                                                                      
3607                  ShortcutInfo info = (ShortcutInfo) i;                                                             
3608                  ComponentName cn = info.getTargetComponent();                                                     
3609                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3610                      filtered.add(info);                                                                           
3611                  }                                                                                                 
3612              } else if (i instanceof FolderInfo) {                                                                 
3613                  FolderInfo info = (FolderInfo) i;                                                                 
3614                  for (ShortcutInfo s : info.contents) {                                                            
3615                      ComponentName cn = s.getTargetComponent();                                                    
3616                      if (cn != null && f.filterItem(info, s, cn)) {                                                
3617                          filtered.add(s);                                                                          
3618                      }                                                                                             
3619                  }                                                                                                 
3620              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
3621                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
3622                  ComponentName cn = info.providerName;                                                             
3623                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3624                      filtered.add(info);                                                                           
3625                  }                                                                                                 
3626              }                                                                                                     
3627          }                                                                                                         
3628          return new ArrayList<ItemInfo>(filtered);                                                                 
3629      }                                                                                                             
3630                                                                                                                    
3631      private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                            

3632              final UserHandleCompat user) {                                                                        
3633          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3634              @Override                                                                                             
3635              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3636                  if (info.user == null) {                                                                          
3637                      return cn.equals(cname);                                                                      
3638                  } else {                                                                                          
3639                      return cn.equals(cname) && info.user.equals(user);                                            
3640                  }                                                                                                 
3641              }                                                                                                     
3642          };                                                                                                        
3643          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   

3644      }                                                                                                             
3645                                                                                                                    
3646      /**                                                                                                           
3647       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
3648       */                                                                                                           
3649      private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
3650              int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
3651              int titleIndex) {                                                                                     
3652                                                                                                                    
3653          Bitmap icon = null;                                                                                       


3654          final ShortcutInfo info = new ShortcutInfo();                                                             
3655          // Non-app shortcuts are only supported for current user.                                                 
3656          info.user = UserHandleCompat.myUserHandle();                                                              
3657          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3658                                                                                                                    
3659          // TODO: If there's an explicit component and we can't install that, delete it.                           
3660                                                                                                                    
3661          info.title = c.getString(titleIndex);                                                                     
3662                                                                                                                    
3663          int iconType = c.getInt(iconTypeIndex);                                                                   
3664          switch (iconType) {                                                                                       
3665          case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
3666              String packageName = c.getString(iconPackageIndex);                                                   
3667              String resourceName = c.getString(iconResourceIndex);                                                 
3668              info.customIcon = false;                                                                              
3669              // the resource                                                                                       
3670              icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);                    
3671              // the db                                                                                             
3672              if (icon == null) {                                                                                   
3673                  icon = getIconFromCursor(c, iconIndex, context);                                                  
3674              }                                                                                                     
3675              // the fallback icon                                                                                  
3676              if (icon == null) {                                                                                   
3677                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3678                  info.usingFallbackIcon = true;                                                                    
3679              }                                                                                                     
3680              break;                                                                                                
3681          case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
3682              icon = getIconFromCursor(c, iconIndex, context);                                                      
3683              if (icon == null) {                                                                                   
3684                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3685                  info.customIcon = false;                                                                          
3686                  info.usingFallbackIcon = true;                                                                    
3687              } else {                                                                                              
3688                  info.customIcon = true;                                                                           
3689              }                                                                                                     
3690              break;                                                                                                
3691          default:                                                                                                  





3692              icon = mIconCache.getDefaultIcon(info.user);                                                          
3693              info.usingFallbackIcon = true;                                                                        
3694              info.customIcon = false;                                                                              
3695              break;                                                                                                
3696          }                                                                                                         
3697          info.setIcon(icon);                                                                                       
3698          return info;                                                                                              
3699      }                                                                                                             
3700                                                                                                                    
3701      Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
3702          @SuppressWarnings("all") // suppress dead code warning                                                    
3703          final boolean debug = false;                                                                              
3704          if (debug) {                                                                                              
3705              Log.d(TAG, "getIconFromCursor app="                                                                   
3706                      + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
3707          }                                                                                                         
3708          byte[] data = c.getBlob(iconIndex);                                                                       
3709          try {                                                                                                     
3710              return Utilities.createIconBitmap(                                                                    
3711                      BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
3712          } catch (Exception e) {                                                                                   
3713              return null;                                                                                          
3714          }                                                                                                         
3715      }                                                                                                             
3716                                                                                                                    
3717      ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                           
3718          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
3719          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
3720          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
3721                                                                                                                    
3722          if (intent == null) {                                                                                     
3723              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
3724              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
3725              return null;                                                                                          
3726          }                                                                                                         
3727                                                                                                                    
3728          Bitmap icon = null;                                                                                       
3729          boolean customIcon = false;                                                                               
3730          ShortcutIconResource iconResource = null;                                                                 
3731                                                                                                                    
3732          if (bitmap instanceof Bitmap) {                                                                           
3733              icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                          
3734              customIcon = true;                                                                                    
3735          } else {                                                                                                  
3736              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
3737              if (extra instanceof ShortcutIconResource) {                                                          
3738                  iconResource = (ShortcutIconResource) extra;                                                      
3739                  icon = Utilities.createIconBitmap(iconResource.packageName,                                       
3740                          iconResource.resourceName, mIconCache, context);                                          

3741              }                                                                                                     
3742          }                                                                                                         
3743                                                                                                                    
3744          final ShortcutInfo info = new ShortcutInfo();                                                             
3745                                                                                                                    
3746          // Only support intents for current user for now. Intents sent from other                                 
3747          // users wouldn't get here without intent forwarding anyway.                                              
3748          info.user = UserHandleCompat.myUserHandle();                                                              
3749          if (icon == null) {                                                                                       
3750              icon = mIconCache.getDefaultIcon(info.user);                                                          
3751              info.usingFallbackIcon = true;                                                                        
3752          }                                                                                                         
3753          info.setIcon(icon);                                                                                       
3754                                                                                                                    
3755          info.title = name;                                                                                        
3756          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3757                  info.title.toString(), info.user);                                                                


3758          info.intent = intent;                                                                                     
3759          info.customIcon = customIcon;                                                                             
3760          info.iconResource = iconResource;                                                                         
3761                                                                                                                    
3762          return info;                                                                                              
3763      }                                                                                                             
3764                                                                                                                    
3765      boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
3766              int iconIndex) {                                                                                      
3767          // If apps can't be on SD, don't even bother.                                                             
3768          if (!mAppsCanBeOnRemoveableStorage) {                                                                     
3769              return false;                                                                                         
3770          }                                                                                                         
3771          // If this icon doesn't have a custom icon, check to see                                                  
3772          // what's stored in the DB, and if it doesn't match what                                                  
3773          // we're going to show, store what we are going to show back                                              
3774          // into the DB.  We do this so when we're loading, if the                                                 
3775          // package manager can't find an icon (for example because                                                
3776          // the app is on SD) then we can use that instead.                                                        
3777          if (!info.customIcon && !info.usingFallbackIcon) {                                                        
3778              cache.put(info, c.getBlob(iconIndex));                                                                
3779              return true;                                                                                          
3780          }                                                                                                         
3781          return false;                                                                                             
3782      }                                                                                                             
3783      void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
3784          boolean needSave = false;                                                                                 
3785          try {                                                                                                     
3786              if (data != null) {                                                                                   
3787                  Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
3788                  Bitmap loaded = info.getIcon(mIconCache);                                                         
3789                  needSave = !saved.sameAs(loaded);                                                                 
3790              } else {                                                                                              
3791                  needSave = true;                                                                                  
3792              }                                                                                                     
3793          } catch (Exception e) {                                                                                   
3794              needSave = true;                                                                                      
3795          }                                                                                                         
3796          if (needSave) {                                                                                           
3797              Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
3798              // This is slower than is ideal, but this only happens once                                           
3799              // or when the app is updated with a new icon.                                                        
3800              updateItemInDatabase(context, info);                                                                  
3801          }                                                                                                         
3802      }                                                                                                             
3803                                                                                                                    
3804      /**                                                                                                           
3805       * Return an existing FolderInfo object if we have encountered this ID previously,                            
3806       * or make a new one.                                                                                         
3807       */                                                                                                           
3808      private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      

3809          // See if a placeholder was created for us already                                                        
3810          FolderInfo folderInfo = folders.get(id);                                                                  
3811          if (folderInfo == null) {                                                                                 
3812              // No placeholder -- create a new instance                                                            
3813              folderInfo = new FolderInfo();                                                                        
3814              folders.put(id, folderInfo);                                                                          
3815          }                                                                                                         
3816          return folderInfo;                                                                                        
3817      }                                                                                                             
3818                                                                                                                    
3819      public static final Comparator<AppInfo> getAppNameComparator() {                                              
3820          final Collator collator = Collator.getInstance();                                                         
3821          return new Comparator<AppInfo>() {                                                                        
3822              public final int compare(AppInfo a, AppInfo b) {                                                      
3823                  if (a.user.equals(b.user)) {                                                                      
3824                      int result = collator.compare(a.title.toString().trim(),                                      
3825                              b.title.toString().trim());                                                           
3826                      if (result == 0) {                                                                            
3827                          result = a.componentName.compareTo(b.componentName);                                      
3828                      }                                                                                             
3829                      return result;                                                                                
3830                  } else {                                                                                          
3831                      // TODO Need to figure out rules for sorting                                                  
3832                      // profiles, this puts work second.                                                           
3833                      return a.user.toString().compareTo(b.user.toString());                                        
3834                  }                                                                                                 
3835              }                                                                                                     
3836          };                                                                                                        
3837      }                                                                                                             
3838      public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
3839              = new Comparator<AppInfo>() {                                                                         
3840          public final int compare(AppInfo a, AppInfo b) {                                                          
3841              if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
3842              if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
3843              return 0;                                                                                             
3844          }                                                                                                         
3845      };                                                                                                            
3846      static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
3847          if (info.activityInfo != null) {                                                                          
3848              return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
3849          } else {                                                                                                  
3850              return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
3851          }                                                                                                         
3852      }                                                                                                             
3853      public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {                
3854          private Collator mCollator;                                                                               
3855          private HashMap<Object, CharSequence> mLabelCache;                                                        
3856          ShortcutNameComparator(PackageManager pm) {                                                               
3857              mLabelCache = new HashMap<Object, CharSequence>();                                                    
3858              mCollator = Collator.getInstance();                                                                   
3859          }                                                                                                         
3860          ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {                                        
3861              mLabelCache = labelCache;                                                                             
3862              mCollator = Collator.getInstance();                                                                   
3863          }                                                                                                         
3864          public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {                    
3865              String labelA, labelB;                                                                                
3866              ComponentName keyA = a.getComponentName();                                                            
3867              ComponentName keyB = b.getComponentName();                                                            
3868              if (mLabelCache.containsKey(keyA)) {                                                                  
3869                  labelA = mLabelCache.get(keyA).toString();                                                        
3870              } else {                                                                                              
3871                  labelA = a.getLabel().toString().trim();                                                          
3872                                                                                                                    
3873                  mLabelCache.put(keyA, labelA);                                                                    
3874              }                                                                                                     
3875              if (mLabelCache.containsKey(keyB)) {                                                                  
3876                  labelB = mLabelCache.get(keyB).toString();                                                        
3877              } else {                                                                                              
3878                  labelB = b.getLabel().toString().trim();                                                          
3879                                                                                                                    
3880                  mLabelCache.put(keyB, labelB);                                                                    
3881              }                                                                                                     
3882              return mCollator.compare(labelA, labelB);                                                             
3883          }                                                                                                         
3884      };                                                                                                            
3885      public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
3886          private final AppWidgetManagerCompat mManager;                                                            
3887          private final PackageManager mPackageManager;                                                             
3888          private final HashMap<Object, String> mLabelCache;                                                        
3889          private final Collator mCollator;                                                                         
3890                                                                                                                    
3891          WidgetAndShortcutNameComparator(Context context) {                                                        
3892              mManager = AppWidgetManagerCompat.getInstance(context);                                               
3893              mPackageManager = context.getPackageManager();                                                        
3894              mLabelCache = new HashMap<Object, String>();                                                          
3895              mCollator = Collator.getInstance();                                                                   
3896          }                                                                                                         
3897          public final int compare(Object a, Object b) {                                                            
3898              String labelA, labelB;                                                                                
3899              if (mLabelCache.containsKey(a)) {                                                                     
3900                  labelA = mLabelCache.get(a);                                                                      
3901              } else {                                                                                              
3902                  labelA = (a instanceof LauncherAppWidgetProviderInfo)                                             
3903                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                                   
3904                          : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                         
3905                  mLabelCache.put(a, labelA);                                                                       
3906              }                                                                                                     
3907              if (mLabelCache.containsKey(b)) {                                                                     
3908                  labelB = mLabelCache.get(b);                                                                      
3909              } else {                                                                                              
3910                  labelB = (b instanceof LauncherAppWidgetProviderInfo)                                             
3911                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                                   
3912                          : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                         
3913                  mLabelCache.put(b, labelB);                                                                       
3914              }                                                                                                     
3915              return mCollator.compare(labelA, labelB);                                                             
3916          }                                                                                                         
3917      };                                                                                                            
3918                                                                                                                    
3919      static boolean isValidProvider(AppWidgetProviderInfo provider) {                                              
3920          return (provider != null) && (provider.provider != null)                                                  
3921                  && (provider.provider.getPackageName() != null);                                                  
3922      }                                                                                                             
3923                                                                                                                    
3924      public void dumpState() {                                                                                     
3925          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
3926          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
3927          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
3928          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
3929          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
3930          if (mLoaderTask != null) {                                                                                
3931              mLoaderTask.dumpState();                                                                              
3932          } else {                                                                                                  
3933              Log.d(TAG, "mLoaderTask=null");                                                                       
3934          }                                                                                                         
3935      }                                                                                                             
3936                                                                                                                    
3937      public Callbacks getCallback() {                                                                              
3938          return mCallbacks != null ? mCallbacks.get() : null;                                                      
3939      }                                                                                                             
















3940  }